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

前端 未结 5 1078
借酒劲吻你
借酒劲吻你 2020-11-30 01:25

I converted my app to ARC and noticed that an object alloc\'ed in one of my view controllers was not being dealloc\'ed when that view controller was dealloc\'ed. It took a w

相关标签:
5条回答
  • 2020-11-30 01:36

    This is a bug that has been acknowledged by Apple in Technical Q&A QA1758.

    You can workaround on iOS 5 and OS X 10.7 by compiling this code into your app:

    #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
    

    You will find more information about this workaround in my blog post Debugging with ARC and Zombies enabled.

    0 讨论(0)
  • 2020-11-30 01:43

    Turns out, I've written some serious nonsense

    If zombies worked like I originally wrote, turning on zombies would directly lead to innumerable false positives...

    There is some isa-swizzling going on, probably in _objc_rootRelease, so any override of dealloc should still be called with zombies enabled. The only thing that won't happen with zombies is the actual call to object_dispose — at least not by default.

    What's funny is that, if you do a little logging, you will actually see that even with ARC enabled, your implementation of dealloc will call through to it's superclass's implementation.

    I was actually assuming to not see this at all: since ARC generates these funky .cxx_destruct methods to dispose of any __strong ivars of a class, I was expecting to see this method call dealloc — if it's implemented.

    Apparently, setting NSZombieEnabled to YES causes .cxx_destruct to not be called at all — at least that's what happened when I've edited your sample project:
    zombies off leads to backtrace and both deallocs, while zombies on yields no backtrace and only one dealloc.

    If you're interested, the additional logging is contained in a fork of the sample project — works by just running: there are two shared schemes for zombies on/off.


    Original (nonsensical) answer:

    This is not a bug, but a feature.

    And it has nothing to do with ARC.

    NSZombieEnabled basically swizzles dealloc for an implementation which, in turn, isa-swizzles that object's type to _NSZombie — a dummy class that blows up, as soon as you send any message to it. This is expected behavior and — if I'm not entirely mistaken — documented.

    0 讨论(0)
  • 2020-11-30 01:44

    Turns out it is an iOS bug. Apple has contacted me and indicated they've fixed this in iOS 6.

    0 讨论(0)
  • 2020-11-30 01:50

    to answer the second question you would need to remove the observer from NSNotification - that will keep it from calling the view.

    Normally, you would do this in the dealloc but with that zombie issue maybe it's not getting called. Maybe you could put that logic in viewDidUnload?

    0 讨论(0)
  • 2020-11-30 01:58

    Because you have open NSZombieEnabled, this let the object not call dealloc, and put the object to a special place. you can close NSZombieEnabled and have try again. And double check if your code have circle retain condition.

    0 讨论(0)
提交回复
热议问题