Beware zombies w/ ARC.

If you’re using Automatic Reference Counting in your IOS project, make sure to turn NSZombieEnabled OFF. If you don’t, parent object deallocation will never deallocate child objects.

In our case, we had a project that was more than a year old, that we recently migrated to ARC. Our project targets are configured as follows:

  • iPad project – ARC ON
  • iPhone project – ARC ON
  • “non arc” project (collection of third party non-arc code) – ARC OFF

The following code shows an example of this in an easy test:

TestArcStrong.h

  1. #import <Foundation/Foundation.h>
  2.  
  3. @interface InnerObject : NSObject
  4. @end
  5.  
  6. @interface TestArcStrong : NSObject
  7. @property (strong) InnerObject * object;
  8. + (void) runTest;
  9. @end

TestArcStrong.m

  1. #import "TestArcStrong.h"
  2.  
  3. @implementation InnerObject
  4. (void)dealloc { NSLog(@"inner dealloc"); }
  5. @end
  6.  
  7. @implementation TestArcStrong
  8. @synthesize object;
  9.  
  10. (void)dealloc { NSLog(@"outer dealloc.."); }
  11.  
  12. + (void) runTest {
  13.     NSLog(@"Hello world, here we go..");
  14.     TestArcStrong * tas = [[TestArcStrong alloc] init];
  15.     tas.object = [[InnerObject alloc] init];
  16. }
  17. @end

Simply add that to your project and call [TestArcStrong runTest]; somewhere in your app. If you don’t see the inner dealloc message logged, try turning off NSZombieEnabled in your project’s run scheme.

Thanks to stack overflow’s auto-suggest-as-you-type tool, I would have never found this thread that led me to the answer without that auto-suggest tool finding similar posts with better results than I was getting myself.

In my opinion, the ARC migration tool and/or xcode running the project should warn when NSZombieEnabled is on if it shouldn’t be used with ARC. Update: The stackoverflow thread mentioned above has an answer in it indicating this is a known bug in IOS5+ and apple has fixed it in IOS6.

P.S. If you haven’t migrated to ARC, you should. The main thing that sold me were auto-nilling weak pointers, which means no more worry about pointers pointing to something that’s already dealloced and causing a crash. And, the @autorelease {} block is pretty badass as well, though you don’t have to have ARC enabled to use that one..