为什么在这段代码中 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
也是自动释放的(在这个方法之外没有任何东西拥有它),但是那是什么,关于 ads
或 adsName
是否首先被释放的 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: 方法自动释放对象,因为它应该作为一种优化而自行保留。在这种情况下,我建议您在从数组中获取对象时调用保留对象,并在此方法结束之前释放它。这对这种情况有帮助。
我只是 运行 进入 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
也是自动释放的(在这个方法之外没有任何东西拥有它),但是那是什么,关于 ads
或 adsName
是否首先被释放的 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: 方法自动释放对象,因为它应该作为一种优化而自行保留。在这种情况下,我建议您在从数组中获取对象时调用保留对象,并在此方法结束之前释放它。这对这种情况有帮助。