I've looked through lots of posts, my books and Apple Developer and gleaned most of the understanding I need on use of these. I would be really grateful if some kind person could confirm that I've got it right (or correct me) and also answer the two questions.
Many thanks,
Chris.
Order of Messages Generally, the messages will appear in the following order:
didReceiveMemoryWarning
viewDidUnload (which can be caused by 1) - obviously only applies to View Controller Classes.
dealloc
didReceiveMemoryWarning
Called when the system is low on memory.
By default, view controllers are registered for memory warning notifications and within the template method, the call to [super didReceiveMemoryWarning] releases the view if it doesn't have a superview, which is a way of checking whether the view is visible or not. It releases the view by setting its property to nil.
Action - Release anything you do not need, likely to be undoing what you might have set up in viewDidLoad. Do not release UI elements as these should be released by viewDidUnload.
Question1 - It seems that this will be called even if the View is visible, so its difficult to see what you could safely release. It would be really helpful to understand this and some examples of what could be released.
viewDidUnload
Called whenever a non visible View Controller's View property is set to nil, either manually or most commonly through didReceiveMemoryWarning.
The viewDidUnload method is there so that you can: - clean up anything else you would like, to save extra memory or - if you've retained some IBOutlets, to help free up memory that wouldn't otherwise be released by the view being unloaded.
Action - generally any IBOutlets you release in dealloc, should also be released (and references set to nil) in this method. Note that if the properties are set to retain, then setting them to nil will also release them.
dealloc
Called when the view controller object is de-allocated, which it will be when the retain count drops to zero.
Action - release all objects that have been retained by the class, including but not limited to all properties with a retain or copy.
Popping View Controllers and Memory
Question 2 - Does popping a view remove it from memory?
Some corrections and suggestions:
didReceiveMemoryWarning
practicesAs you said, the controller's default implementation of didReceiveMemoryWarning
releases its view if it is 'safe to do so'. While it's not clear from Apple's documents what 'safe to do so' means, it is generally recognized as it has no superview (thus there is no way that the view is currently visible), and its loadView
method can rebuild the entire view without problems.
The best practice when you override didReceiveMemoryWarning
is, not to try releasing any view objects at all. Just release your custom data, if it is no longer necessary. Regarding views, just let the superclass's implementation deal with them.
Sometimes, however, the necessity of the data may depend on the state of your view. In most cases, those custom data is set in viewDidLoad
method. In these cases, 'safe to release custom data' means that you know that loadView
and viewDidLoad
will be invoked before the view controller uses the custom data again.
Therefore, in your didReceiveMemoryWarning
, call the superclass implementation first, and if its view is unloaded, then release the custom data because you know that loadView
and viewDidLoad
will be invoked again for sure. For example,
- (void)didReceiveMemoryWarning {
/* This is the view controller's method */
[super didReceiveMemoryWarning];
if (![self isViewLoaded]) {
/* release your custom data which will be rebuilt in loadView or viewDidLoad */
}
}
Be careful not to use self.view == nil
, because self.view
assumes that the view is needed for someone and will immediately load the view again.
viewDidUnload
methodviewDidUnload
is called when the view controller unloaded the view due to a memory warning. For example, if you remove the view from the superview and set the view
property of the controller to nil
, viewDidUnload
method will not be invoked. A subtle point is that even if the view of a view controller is already released and set to nil by the time the controller receives didReceiveMemoryWarning
, so actually there is no view to unload for the controller, viewDidUnload
will be invoked if you call the superclass's implementation of didReceiveMemoryWarning
.
That's why it's not a good practice to manually set the view
property of a view controller to nil. If you do, you may better send a viewDidUnload
message as well. I guess your understanding of viewDidUnload
is more desirable, but apparently it's not the current behavior.
If you mean 'removing from the superview' by 'popping', it does decrease the retain count of the view, but not necessarily deallocate it.
If you mean popping out from a UINavigationController, it actually decrease the retain count of the view controller itself. If the view controller is not retained by another object, it will be deallocated, desirably with its view. As I explained, viewDidUnload
will not be invoked this time.
Technically, the retain count may not go down to zero. The object is more likely to be just deallocated without setting the count to zero beforehand.
Just to make sure, the view controller itself is normally not deallocated by default behaviors due to the memory warning.
didReceiveMemoryWarning
...
Action - Release anything you do not need, likely to be undoing what you might have set up in viewDidLoad.
This is wrong. Anything that you recreate in viewDidLoad
should be released (and set to nil
) in viewDidUnload
. As you mention below, didReceiveMemoryWarning
is also called when the view is visible. In didReceiveMemoryWarning
, you should release stuff like caches or other view controllers you are holding on to that can be recreated lazily the next time they are required (i.e., by implementing their getter manually).
viewDidUnload
...
Action - generally any IBOutlets you release in dealloc, should also be released (and references set to nil) in this method. Note that if the properties are set to retain, then setting them to nil will also release them.
Correct. Generally, everything you create in viewDidLoad and all IBOutlets that are declared as retain
should be released and set to nil
here.
dealloc
...
Action - release all objects that have been retained by the class, including but not limited to all properties with a retain or copy.
Correct. It's worth noting that this includes all objects you handle in viewDidUnload
because the latter is not implicitly called in the dealloc
process (AFAIK, not entirely sure). That's why it is essential to set all releases objects to nil
in viewDidUnload
because otherwise you risk releasing something twice (first in viewDidUnload
, then again in dealloc
; if you set the pointer to nil
, the release call in dealloc
will have no effect).
Popping View Controllers and Memory
Question 2 - Does popping a view remove it from memory?
Not necessarily. That is an implementation detail that you should not be concerned about. Whatever the current practice is, Apple could change it in the next release.
Just to update this thread to make it iOS6-relevant:
viewDidUnload and viewWillUnload were deprecated in iOS6. These methods are never called.
For this and other deprecated methods, see: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/DeprecationAppendix/AppendixADeprecatedAPI.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With