Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dealloc not being called on ARC app

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

like image 412
rob Avatar asked Feb 09 '12 21:02

rob


6 Answers

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];
        }
    }];
like image 69
mikeq Avatar answered Nov 08 '22 12:11

mikeq


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

like image 37
Almas Sapargali Avatar answered Nov 08 '22 14:11

Almas Sapargali


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.

like image 21
Dean Liu Avatar answered Nov 08 '22 13:11

Dean Liu


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.

like image 16
jbbenni Avatar answered Nov 08 '22 13:11

jbbenni


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;

like image 15
kgaidis Avatar answered Nov 08 '22 14:11

kgaidis


Here's another tip (happened to me):

tl;dr: Look at your class instance variables as well, not just the class properties. Are you allocating any instance variable in code, and not setting it to nil later?

I had a class with a bunch of properties (@property (nonatomic, strong) and @property (nonatomic, weak)) in its header file. I commented out those properties one by one to see whether this will change anything. It did not. The main class was still not being deallocated. So the problem was not in the properties.

What I did afterwards was look at the instance variables. I had one instance variable (which was a UIViewController), which I created on viewDidLoad. This one never got dealloc-ed!

When I removed this variable, sure enough, my main class called dealloc.

So because this one wasn't dealloc-ed, my main class was not dealloc-ed either. Moving that instance variable as a property solved the problem for me.

Question: I'm not sure why this happens though. Does the operating system have better control over the properties of a class, than over the instance variables? It seems a bit weird that the parent class which contains the instance variable doesn't get released because of its instance variable.

like image 10
Alex Avatar answered Nov 08 '22 12:11

Alex