The cool feature in iOS is that it calls certain methods in your ViewControllers when it encounters Low Memory. The following methods are called when the iOS encounters a Low Memory and warns your ViewControllers about it.
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
Most developers know about that the above methods are called when Memory is Low, but do not know what exactly to do in these methods. Well In this post I am going to explain whatever doubts you might have regarding Properties and Nibs and how to handle them in these methods.
First of all we need to understand What are ObjectiveC Properties ?
@property (nonatomic, retain) MyClass *obj;
and in your .m file
@synthesize obj;
and in your dealloc method add this line
[obj release];
you assign your ViewController to handle this in the following way:
Assign the newly allocated "tempObj" to your property "obj" and release "tempObj" because it is retained by your property "obj".MyClass *tempObj=[[MyClass alloc] init];//tempObj retain count=1
[self setObj:tempObj]; //tempObj retain count=2
[tempObj release]; //tempObj retain count=1
After this you can also do this if you want to:
This will release any previous instances retained by your property "obj" and assign it to "nil" hence not leaking any memory. This right here is the beauty of Properties. Even if you would have assigned it some new object, it would have first released the previously retained instance and then retained the new object.[self setObj:nil]; //tempObj retain count=0
So this means that we do not need to call release on our properties except for our dealloc method:
Now that we know what Properties can do. We just need to understand that how iOS wants you to react to Memory Warnings it generates in Low Memory conditions.[obj release]; // only in dealloc methods.
[self setObj:nil]; // in other methods.
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
Then iOS releases the NIB file loaded for that ViewController and calls "viewDidUnload" method. In this method you must assign your properties to nil.
So that your ViewController object is drained from the memory and has nothing but some placeholder iVars(properties) that have nil values. This will clear up the memory and your app can work fine after this.
That is all there is to know about memory management in Objective C and iOS.
Question: But this really wouldn't help my app to work fine or would it (I just lost all my data)? how can I re-assign my Properties? What will happen to my currently visible ViewController? Will I loose on screen data?
Answer: It did help your app to work fine actually. If you are in a Navigation Stack this really helped your application in running out of memory.
That means all your vViewControllers are in UINavigationController's stack then the following will happen:
UINavC > VC1 > VC2 > VC3
Suppose you are in VC3 and receive a memory warning, maybe because you are loading a big PDF document in there, then iOS will call the Memory Warning methods i.e "didRecieveMemoryWarning" & "viewDidUnload" in the whole Navigation Stack except in your visible ViewController VC3. Hence not loosing the currently being displayed information. Now as you go back(popViewController:VC3) to VC2, which has already gone under the process of releasing all its outlets and datasource perhaps, iOS will reload the VC2 Nib file and will call "viewDidLoad" method on VC2 giving it a chance to reassign its iVars all over again. That is why in most implementations "viewDidLoad" is thee method where you assign values to properties and get data sources etc. And since on popping VC3 it gets released by the UINavigationController the memory will reduce automatically.
- (void)viewDidLoad
{
[super viewDidLoad];
}
Then as you go and pop VC2, VC1 will get loaded again and so on and so forth.
I am not sure if this is the same case with UITabBarController at this point but you can give it a try.
It is pretty simple but you have to take care of this sequence when you are writing down your ViewControllers implementation. Not to put something that will get released once you receive a memory warning but will not get it back once the "ViewDidLoad" is called again on your ViewController.
So plan ahead of things.
I hope you gained something out of it.
Write your questions or suggestions below if you have any.
