tags:

views:

311

answers:

3

I have seen code (probably Apple's own sample code) written in such a way where it releases the ivar in dealloc and setting the property in viewDidUnload.

e.g.

  • (void)viewDidUnload { self.navigationController = nil; }

  • (void)dealloc { [_navigationController release]; }

Why do them in two places? Also, why set nil in one and release in another. It seems that self.property = nil would just take care of everything since it would release and set the ivar to nil.

+3  A: 

You're right: you can indeed do self.property = nil everywhere, including dealloc. The only downside is that if the setter method does anything more complicated than just releasing the ivar, you might end up trying to access other fields that have already been released, etc.

As for why you also release the outlet in viewDidUnload, that's a memory optimization. Since the stuff you release in viewDidUnload are things that will be reinstantiated when the view is loaded again, releasing them there frees up memory in low-memory situations.

Daniel Dickison
Thanks, so in that case the viewDidUnload code could have used the same code as dealloc for releasing the object, i.e. [_navigationController release] rather than setting it to nil, right?
Boon
Yes, but don't. Use the accessor everywhere except in -dealloc. Use of accessors in -dealloc is controversial for the reasons Daniel gave (Apple is unclear on what they recommend, too). Just get in the habit of releasing all your retained ivars in -dealloc. Don't bet on some other thing to do it for you. And anytime you release something, set it to nil. Much of ObjC is without a safety net; good habits are what keep your programs working because the compiler won't save you. (OK, maybe Clang will finally save us, but only use it's power for good.)
Rob Napier
A: 

If you're relying on garbage collection (available in Objective-C 2.0) then setting the ivar to nil and calling release will achieve the same end.

I'm guessing that the code you're looking at is managing the memory with release and only setting it to nil so that you don't later try to access an object that is no longer there. The nil is more bookkeeping than memory management when you're not relying on the GC.

Naaff
Not quite -- -[anObject release] will not do anything (it's a nop) under GC, while setting to nil will allow the garbage collector to eventually free the object (it's removing a reference), unless the ivar's defined as a weak reference.
xtophyr
+1  A: 

Apple recomments that you not call setters in the init and especially dealloc routines.

This is due to the fact that the object is only partially set up at this time, and setters could have observers attached to them, or could be overridden by subclasses, and otherwise have undesirable affects during dealloc, or could be confused during init with a partially configured object.

Hence, you normally use:

_navigationController = [[NavController alloc] init];

style code in your init routine,

[_navigationController release];

style code in your dealloc, and setters in other code where the object is known to be fully complete.

Some cases to consider:

  • Subclass overrides setNavigationController and references its own ivars allocated by init. Crash on init.
  • Subclass overrides setNavigationController and references its own ivars released in dealloc. Crash on dealloc.
  • Subclass overrides setNavigationController and redraws some parts of the screen. Pointless waste of cycles, or glitchy display.
  • Other objects being deallocated at the same time observe navigationController and those observers fire during dealloc
  • etc
Peter N Lewis