为什么在这段代码中 NSString 变成了 NSZomie?

Why dose the NSString become NSZomie in this code?

我只是 运行 进入 problem.I 使用 NSMutableArray 来保存需要加载的广告 ID。预加载一个 id 后,我将其从数组中删除。然后我发现,删除后,单位id变成了僵尸。

我试图重现这个,我发现当从数组中提取广告 ID 时,它不是 zombie.It 只是从数组中删除后变成僵尸。但是,仍然有一个 NSString* 引用它,怎么会这样呢?如果此时它会变成僵尸,它应该每次都变成僵尸。但它只是偶尔发生。

 -(void)preloadNextRewardVideo
 {
     if([_allRewardVideoAds count])
     {
         NSString* adsName = [_allRewardVideoAds objectAtIndex:0];  //the element is not a zombie here
         GADRewardBasedVideoAd* ads = [self ensureRewardVideo:adsName];
         if(![ads isReady])
         {
             _currentRewardVideoName = adsName;
             [_allRewardVideoAds removeObjectAtIndex:0];
             GADRequest *request = [GADRequest request];
             [ads loadRequest:request withAdUnitID:adsName];  //here, adsName is a zombie
             _isRewarLoading = YES;
         }
     }
 }

值得仔细看看 cocoa 的 memory management policies。这里的事情(在我看来)是,当您的代码分配字符串 adsName 时,preloadNextRewardVideo 方法所属的对象不会取得 string-object 的所有权,而 adsName 是指向(在此上下文中,'ownership' 意味着通过 alloc/init、新建、复制等为其分配和初始化 space,或者向其发送显式保留消息)。您所拥有的只是一个指向 _allRewardVideoAds 数组所拥有的 string-object 的局部变量。是的,进行赋值会增加保留计数,但保留是自动释放的,并且仅限于此方法的范围。一旦此方法结束,没有任何东西会拥有那个 string-object,它将被释放。

这不会是一个问题(并且不会创建 NSZombie 标志)除了你刚刚将 adsName 发送到另一个对象(GADRewardBasedVideoAd* ads),我猜它不会保留它任何一个。当然,ads 也是自动释放的(在这个方法之外没有任何东西拥有它),但是那是什么,关于 adsadsName 是否首先被释放的 race-condition 是什么?我怀疑你 do 有一个 race-condition 因为 NSZombie 只是有时出现,但我对 autorelease 的内部机制了解不多,不知道它是如何工作的。

我认为 NSZombie 只是告诉你你有一个对象是:

  • 正在被外部对象使用,并且
  • 将很快通过自动释放销毁。

ARC 预计会出现问题,并使用 NSZombie 通知您。

您可以通过使用 属性 setter(例如使用 self.currentRewardVideoName = adsName)为该对象全局保留 string-object 或通过在本地复制它来解决此问题(NSString* adsName = [[_allRewardVideoAds objectAtIndex:0] copy]) 这确保您的对象拥有方法末尾的字符串。

由于您没有启用ARC,这意味着您需要自己手动管理内存。由于您没有启用 ARC,这意味着您需要自己手动管理内存。尽管大多数 API 都会 return 从方法中自动释放对象,但情况并非总是如此。

对于这种情况,NSArray 会保留其自身包含的对象,因此它可能不需要 return 从 objectAtIndex: 方法自动释放对象,因为它应该作为一种优化而自行保留。在这种情况下,我建议您在从数组中获取对象时调用保留对象,并在此方法结束之前释放它。这对这种情况有帮助。