Dealloc not being called on ARC app

35,488

Solution 1

I just ran across a similar issue. Do you have any blocks where you are referring to 'self'? I had some blocks for notification observation in my init where I was referring to 'self'. Under ARC self is retained in blocks. My dealloc wasn't getting called and that was where I was removing the observation.

The trick is to create a __weak (iOS 5+) or __unsafe_unretained (iOS 4.x) reference to your 'self' and use that to access self or any _iVars (these will cause 'self' to be retained as well) in the block. Here's an example.

__unsafe_unretained TableViewController *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
        if (weakSelf.tableView) {
            [weakSelf.tableView reloadData];
        }
    }];

Solution 2

In my case it was NSTimer. It retains its target so you need to invalidate timer when you're done with view controller.

Solution 3

If dealloc is not being called by the VC, then I would bet there is a circular reference somewhere in your code, which is preventing ARC from calling dealloc.

Some things to check:

  1. Do you have an object instantiated that references back to the VC?
  2. If you need to reference the VC be sure you have used '__unsafe_unretained' attribute or 'weak' (iOS5+) so that the retain cycle does not occur.

I was nipped in the butt when my delegate declarations did not utilize __unsafe_unretained.

Solution 4

Even with ARC you can inspect the reference count manually:

CFIndex rc = CFGetRetainCount((__bridge CFTypeRef)myObj);

You can know for sure if your code is hung in a memory cycle.

Solution 5

My problem was delegates.

Check your delegates! The delegate property should have weak specified:

weak var delegate: SomeProtocol?

or

@property (weak, nonatomic) id<SomeProtocol> delegate;

Share:
35,488
rob
Author by

rob

I mainly do iOS, but have a spotty past in hardware.

Updated on March 25, 2020

Comments

  • rob
    rob about 4 years

    I have a UIViewController that is pushed onto a container controller and then popped off, and using the allocations instrument, I can see that the view controller is destroyed afterwards. However, a breakpoint in the controller's dealloc is never reached. Does anyone know why dealloc isn't called? Is it possible for ARC to destroy an object without calling dealloc?

    Also, I've disabled NSZombies (some have said that can cause dealloc not to fire).

    Edit:

    Dealloc doesn't do much, just prints to the console, and it never gets called:

    - (void)dealloc { NSLog(@"Deallocating..."); }

    I can't post the container controller–it's proprietary and too complicated. Dealloc is called consistently on some controllers and not others. If I can find the time I will try and post a simplified version that reproduces the problem.

    Is there any way to verify that NSZombies is disabled?

    Edit2

    I'm posting a screenshot from instruments; it looks to me like it's properly deallocating.

    enter image description here

  • jbbenni
    jbbenni about 11 years
    I agree with @Dean Liu - Instruments not withstanding, I suspect it isn't deallocating due to a memory cycle. I occasionally get snagged with cycles using Blocks - especially if the block references 'self', it is very easy to do.
  • leviathan
    leviathan almost 11 years
    After code reviewing lots of migrated code (from non-arc projects to arc projects), I can confirm that this is a major source of undesired retain-cycles. In the end: a block comes in handy and is easily created, right!
  • user102008
    user102008 over 10 years
    By not unregistering the observer, that means it will fire in response to the notification forever, even after self is long gone. And if you add this observer multiple times, then each time this notification happens, it will fire multiple useless observers, forever. This cannot be good programming practice.
  • Nat
    Nat about 10 years
    For simplicity we can use __weak typeof(self) weakSelf = self;
  • Chris Prince
    Chris Prince over 9 years
    This helped! (It sure would be nice if there was a corresponding function call method that gave a list of all the objects that referenced an object).
  • k06a
    k06a over 9 years
    [NSNotificationCenter addObserverForName:object:queue:usingBlock:] returns an opaque object to act as the observer. You need to unsubscribe.