Sending release to an NSArray of UIViewControllers?
If I have an NSArray of UIViewControllers and send release to the array, will that call viewDidUnload or dealloc for each of the UIViewControllers? or neither?
Here's what I'm doing:
- (void) viewDidLoad {
UIViewController* profileController = [[ProfileController alloc] init];
..........
//all the other controllers get allocated same way
self.viewControllers = [[NSMutableArray alloc] initWithObjects: profileController, dietController, exerciseController, progressController, friendsController, nil];
[profileController release];
//other controllers g开发者_开发知识库et released same way ....
}
- (void) dealloc {
[viewControllers release];
NSLog("DEALLOC!");
//I know dealloc is being called
//what happens to the view controllers?
}
I put a breakpoint in the viewDidUnload and dealloc methods for each of these view controllers, and they don't get called.
As pgb mentioned, you are confusing the two concepts of memory management and view controller life cycle. viewDidUnload
will be called whenever the view controllers view is unloaded, which of course will only happen if the view is loaded. In the absence of displaying any of the view controllers you should not expect to see viewDidUnload
called at all.
You very much should expect to see dealloc
called though!
Your problem is with the initialisation of the viewControllers
array:
self.viewControllers = [[NSMutableArray alloc]
initWithObjects: profileController,
dietController,
exerciseController,
progressController,
friendsController,
nil];
Assuming that viewControllers
is a property that is using the retain attribute, this will leak the array, and thus all the array's contents. The problem is that you have alloc'd a mutable array (thus retain count = 1), then you are assigning it to the viewControllers property which will increment the retain count.
In your dealloc method you (correctly) release the array, but this will merely decrement the retain count to one.
My suggested fix is to add autorelease
to the above code:
self.viewControllers = [[[NSMutableArray alloc]
initWithObjects: profileController,
dietController,
exerciseController,
progressController,
friendsController,
nil] autorelease];
After making this change you should expect to see dealloc
being called on the view controllers. You should also expect to see viewDidUnload
called as the views of these view controllers are unloaded (for example, as they are popped off of the stack in a navigation-controller based application).
I see two issues here, one for each of the methods not called:
viewDidUnload
won't be called if the view
associated with the UIViewController
wasn't loaded. You are basically mixing two concepts: memory management (and object lifecycle) vs. view controller life cycle. While you can see some parallelism between the two, they are not necessarily related.
Are you, at any point, pushing the viewController
so its view is visible? If you are not, then viewDidUnload
will certainly not be called (as won't viewDidLoad
).
As for dealloc
, if it's not called after you release the object (and you think the object should be dealloc
ed from memory) it's because you have a memory leak. In your code, I can easily see the memory leak on the initialization code:
UIViewController* profileController = [[ProfileController alloc] init];
..........
//all the other controllers get allocated same way
self.viewControllers = [[NSMutableArray alloc]
initWithObjects: profileController,
dietController,
exerciseController,
progressController,
friendsController,
nil];
profileController
gets its retainCount
bumped on the first line, when you alloc
it. Later, when you add it to a NSMutableArray
, the array will retain
it, bumping its retainCount
once again. To balance that, you would need to release
twice, but you are only release
ing once, on your dealloc
method. To solve this issue, I would change your initialization to:
UIViewController* profileController = [[[ProfileController alloc] init] autorelease];
..........
//all the other controllers get allocated same way
self.viewControllers = [[NSMutableArray alloc]
initWithObjects: profileController,
dietController,
exerciseController,
progressController,
friendsController,
nil];
which will add the extra release
you are missing and balance the retain
release
calls on your view controllers.
When you release the array, that does not dealloc it, that gives it permission to be dealloced if there are no other retains.
Similarly, if the array is dealloced, each element inside is released, but the objects may be retained elsewhere and hence are not guaranteed to be dealloced immediately.
In general, an object like a view or view controller is retained by the UI logic while it's actively being presented, so releasing your retains on it, either directly or through the array, will not cause it to be dealloced if it's being displayed (or, eg, in the stack of a navigation controller).
精彩评论