Coming from environments that rely entirely on garbage collection, the reference counting scheme in Cocoa still bites me. As I’m trying to clean up after myself I sometimes release things I shouldn’t. My yesterday’s blunder was similar to this:
// add new person to the list Person *person = [[Person alloc] init]; person.name = @"Joe"; [people addObject:person]; [person release]
I hear you: What was I thinking? I was thinking that the
people collection (instance of NSMutableArray) will retain its elements as they are added, incrementing their reference count. This is, of course, not the case. Why would I expect such behavior?
Earlier I worked on a navigation app using table views. As the user taps on a row in a table view the app displays the detailed view of the selection:
PersonDetailController *detailController = [[PersonDetailController alloc] initWithNibName:@"PersonDetailView" bundle:[NSBundle mainBundle]]; // omitted: assign selected person to detail controller [self.navigationController pushViewController:detailController animated:YES]; [detailController release];
The navigation controller maintains a stack of view controllers, and because it retains the controllers pushed on the stack, we need to release the pointer.
It’s important to understand the behavior of components in Cocoa framework. Aaron Hillegass mentions two rules concerning release:
- Objects created by alloc, new, copy, or mutableCopy have a retain count of 1 and are not in the autorelease pool.
- If you get an object by any other method, assume that it as a retain count of 1 and is in the autorelease pool. If you do not wish it to be deallocated with the current autorelease pool, you must retain it.