繁体   English   中英

为什么在使用ARC + NSZombieEnabled时未取消分配对象

[英]Why is object not dealloc'ed when using ARC + NSZombieEnabled

我将我的应用程序转换为ARC,并注意到在取消分配视图控制器时,未在其中一个视图控制器中分配的对象被取消分配。 花了一段时间才弄清楚原因。 我在调试时为我的项目启用了“启用僵尸对象”,这是原因。 考虑以下应用逻辑:

1)用户在RootViewController中调用动作,该动作导致创建并通过presentModalViewController:animated呈现SecondaryViewController

2) SecondaryViewController包含一个ActionsController ,它是一个NSObject子类。

3) ActionsController在初始化时会通过NSNotificationCenter观察通知,并在取消分配时停止观察。

4)用户关闭SecondaryViewController返回RootViewController

关闭“启用僵尸对象”后,上面的方法可以正常工作,所有对象都被释放。 即使在SecondaryViewController被取消分配的情况下,在ActionsController上启用Enable Zombie Objects也不会被取消分配。

这在我的应用程序b / c NSNotificationCenter导致了问题,继续将通知发送到ActionsController ,结果处理程序导致应用程序崩溃。

我在https://github.com/xjones/XJARCTestApp创建了一个简单的应用程序来说明这一点。 查看启用/禁用启用僵尸对象的控制台日志以进行验证。

问题

  1. 启用僵尸对象是否正确?
  2. 我应如何实施这种逻辑以消除此问题。 我想继续使用启用僵尸对象。

编辑#1:根据Kevin的建议,我已将此文件提交给了Apple和openradar,网址为http://openradar.appspot.com/10537635

编辑#2:澄清一个好的答案

首先,我是一位经验丰富的iOS开发人员,并且完全了解ARC,僵尸对象等。当然,如果我缺少任何东西,我将感谢您提供任何启发。

其次,确实,针对此特定崩溃的解决方法是,在取消释放secondaryViewController时,将actionsController作为观察者移除。 我还发现,如果在secondaryViewController取消分配时我显式设置了actionController actionsController = nil ,它将被取消分配。 这两个都不是很好的解决方法b / c,它们实际上要求您使用ARC,但要像不使用ARC一样进行编码(例如,在dealloc中明确使用nil iVars)。 特定的解决方案也无助于确定何时其他控制器中会出现此问题,因此开发人员可以确定地知道何时/如何解决此问题。

一个好的答案将说明如何确定地知道在使用ARC + NSZombieEnabled时需要对对象做一些特殊的事情,因此它将解决此特定示例,并且通常还应用于整个项目,而没有其他类似的可能性问题。

完全可能不存在一个好的答案,因为这可能是XCode中的错误。

谢谢大家!

原来,我已经写了一些严重的废话

如果僵尸像我最初写的那样工作,打开僵尸将直接导致无数误报。

可能在_objc_rootRelease发生了一些isa _objc_rootRelease ,因此仍应在启用僵尸的情况下调用对dealloc任何覆盖。 僵尸不会发生的唯一事情是对object_dispose的实际调用-至少在默认情况下不是这样。

有趣的是,如果您进行一些日志记录,您实际上会看到,即使启用了ARC,您的dealloc实现也将调用其超类的实现。

我实际上以为根本看不到这一点:由于ARC生成了这些时髦的.cxx_destruct方法来处理类的任何__strong ivars,因此我期望看到方法称为dealloc (如果已实现)。

显然,将NSZombieEnabled设置为YES .cxx_destruct不会调用.cxx_destruct至少那是我编辑示例项目时发生的情况:
僵尸关闭会导致回溯并同时进行两个dealloc,而僵尸打开不会产生回溯,而只会进行一次dealloc。

如果您感兴趣的话,额外的日志记录将包含在示例项目的fork中 -只需运行即可运行:有两种共享的僵尸开/关方案。


原始(荒谬)的答案:

这不是错误,而是功能。

它与ARC无关。

NSZombieEnabled基本上碎冰鸡尾酒dealloc的,反过来,ISA-碎冰鸡尾酒该对象的类型来实现_NSZombie -这打击了一个虚拟的类,只要你发送任何信息给它。 这是预期的行为,并且-如果我没有完全误解的话-记录在案。

这是Apple在技术问答QA1758中已确认的错误。

您可以在iOS 5和OS X 10.7上解决此问题,方法是将此代码编译到您的应用中:

#import <objc/runtime.h>

@implementation NSObject (ARCZombie)

+ (void) load
{
    const char *NSZombieEnabled = getenv("NSZombieEnabled");
    if (NSZombieEnabled && tolower(NSZombieEnabled[0]) == 'y')
    {
        Method dealloc = class_getInstanceMethod(self, @selector(dealloc));
        Method arczombie_dealloc = class_getInstanceMethod(self, @selector(arczombie_dealloc));
        method_exchangeImplementations(dealloc, arczombie_dealloc);
    }
}

- (void) arczombie_dealloc
{
    Class aliveClass = object_getClass(self);
    [self arczombie_dealloc];
    Class zombieClass = object_getClass(self);

    object_setClass(self, aliveClass);
    objc_destructInstance(self);
    object_setClass(self, zombieClass);
}

@end

您可以在我的博客文章“ 启用ARC和Zombies进行调试”中找到有关此解决方法的更多信息。

原来这是一个iOS错误。 苹果已与我联系,并表示他们已在iOS 6中修复此问题。

因为您已经打开了NSZombieEnabled,所以这使对象不调用dealloc,并将对象放在一个特殊的位置。 您可以关闭NSZombieEnabled,然后重试。 并再次检查您的代码是否具有圆保持条件。

要回答第二个问题,您需要从NSNotification中删除观察者-这将阻止它调用视图。

通常,您可以在dealloc中执行此操作,但由于存在僵尸问题,可能未调用它。 也许您可以将这种逻辑放入viewDidUnload中?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM