I am new to iPhone development.
I am using some buttons and labels in my app. I am releasing all these buttons and labels in dealloc function.
I am also releasing them in viewDidUnload.
- (void)viewDidUnload
{
[super viewDidUnload];
self.ans1 = nil;
self.ans2 = nil;
self.ans3 = nil;
self.ans4 = nil;
self.button = nil;
self.button2 = nil;
self.button3 = nil;
self.button4 = nil;
}
I just want to know that it is good for memory management or it makes no difference to memory management.
And why we use that??
Thanks in advance..!!
it is not the view controller that is unloaded when viewDidUnload is called but only its view. The view controller stays alive until it is deallocated.
In viewDidUnload, you have to release those objects that are part of the view and everything that can and will be recreated in viewDidLoad (because viewDidLoad will be called again when the view controller need to recreate its view). This includes all your outlets. You also have to set these variables to nil to avoid overreleasing them.
Because in dealloc, you should release all objects your view controller retains, including those you included in viewDidUnload.
viewDidUnload is used to release anything that you might have made when the view is created - this included things in viewDidLoad but also includes and IBOutlet properties that are created from inside a xib file. these should all be released and set to nil in viewDidUnload.
Anything else should just be released in dealloc.
The idea is that if viewDidUnload is called to free some memory, the view can be recreated again completely from your viewDidLoad method.
Also see this question;
memory management on the iPhone with viewDidUnload
It is good for memory management. If you release objects associated with a View controller when the controller unloads, you effectively reduce the memory footprint of your application. Retaining objects even when you are not using them makes your application more prone to memory warnings & eventual termination.
Hence, it is good practice to allocate in ViewDidLoad & release in ViewDidUnload.
HTH,
Akshay
Related
I am finishing up an iPad application, and for me, that means filling in all of the dealloc methods in my classes.
I have many views in my nib and most of them contain subviews (i.e. UIViews, UILabels, etc.). Should I release the child views before releasing the parent? If the parent view is released, will its child views be released, as well?
Sample:
-(void)dealloc
{
[super dealloc];
[childView release]; // Do I need this if I use the next line?
[parentView release]; // Will this perform the line above?
}
Both childView and parentView are properties of my view controller. Both have been retained.
Anything that you have retained (whether explicitly or through a retained property) needs to be released for the memory management to be balanced.
Also, you should invoke [super dealloc] at the end of your dealloc implementation, not the beginning (for instance, because you might depend on superclass resources still being available at the time).
By the way, saving your dealloc-writing until you're finishing up work on the app is a backwards way to go. I know it seems like house-cleaning work, but the fact is until you're managing memory properly, you're going to have a very skewed view of how your app really performs.
Ideally you should write your dealloc calls as you write your #synthesize statements. In other words, you add a property to your class, you set it up as a retained property, you write its #synthesize and -release code. That way you know your memory management is basically clean (I mean, at the class property level anyway) and you can code with confidence.
Since you specified that you have subviews from a NIB, it sounds like you also may need to pay close attention to the viewDidUnload method.
Any views which are automatically allocated from the nib you can implicitly release by setting the outlet to nil. For example:
- (void)viewDidUnload {
[super viewDidUnload];
self.subviewOutletOne = nil;
self.subviewOutletTwo = nil;
}
Then for any objects which you explicitly retain, you release them in the dealloc method like you are planning to do:
- (void)dealloc {
[myDataArray release];
[coolAnimatedImage release];
[myCustomSubview release];
[super dealloc];
}
Also be sure to check out the LEAKS instrument. This is a random tutorial for using the built in leak analysis tool. There may be others / better ones. It can a pain to get up and running the first time but is completely worth it.
where i should release objects: in method dealloc or viewDidUnload?
Thanks
The correct way is to release them and set them to nil in both of those methods.
You need to release your objects in viewDidUnload since memory warnings can happen, and if your view doesn't have a superview then you should release your outlets to save memory. The framework will issue a viewDidLoad again if the view was unloaded.
You need to release your objects in dealloc, since viewDidLoad + viewDidUnload is not necessarily called.
Finally you need to set your variables to nil in both of the methods, to not be able to call release on them the second time.
A short answer for you question: dealloc()
A long and more complicated answer for your question: both
release any unused IBOutlets in viewDidUnload(). This method will be called when your device is running out of memory.
release any objects that the current view controller is responsible for memory management, and release them in dealloc(). (An autoreleased object doesn't belong to this category)
Any objects allocated and/or retained as part of loadView and/or viewDidLoad should be released in viewDidUnload. Releasing anything you alloc in viewDidLoad is easy to grasp, loadView is a bit harder if you are using a NIB. Any IBOutlet that is a property defined as retain will be implicitly retained as part of loadView.
If the view have for example a subview that is a UITextField and you connect this view to a property defined as:
#property(nonatomic, retain) IBOutlet UITextField* nameField;
Then the actual text field when loaded from the NIB will have a retain count of +2. +1 because of it's parent view, and +1 because of the property you connected it too. Thus it's memory is not freed until the view controller is released, or the NIB is loaded again.
Unfortunately viewDidUnload is not called when a view controller is deallocated. So you must explicitly release all your `IBOutlets here as well. I use this patter in order to not forget to release anything:
-(void)releaseOutlets {
// Set all outlets to nil
}
-(void)viewDidUnload {
[self releaseOutlets];
[super viewDidUnload];
}
-(void)dealloc {
[self releaseOutlets];
// Release anything else.
[super dealloc];
}
dealloc this way if the parent object is released the child objects will be released as well.
I saw this code in the project template and a few other sample projects.
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
Can someone explain to me what self.myOutlet = nil does? Does it release the memory? I thought you put [myOutlet release] in - (void)dealloc to release the memory. what is = nil? and when do you need to do this?
If myOutlet is specified as a #property (retain) then whenever you assign it to point to a new object, the old one will be released and the new one retained. When you assign it to nil, that therefore releases the object that it previously pointed to.
Typically viewDidUnload method is called when low memory warning occurred and controller's view gets unloaded (controller itself stays in memory). As David pointed in his answer usually outlets are being retained by controller so they stay in memory even after the main view is gone - that reduces the benefits of unloading the view.
You still need to release you outlets in dealloc method even if you release them in viewDidUnload
For more details see this SO question
I'm writing iPhone application which uses multiple views, each with own controller. They are loaded programmatically using initWithNibName: and released before switching to other controller, so only one view is visible at a time.
After releasing view controller (I have checked that dealloc is called) not all memory is freed. I do release all outlets when deleting controller. Also, setting self.view to nil in controller's dealloc doesn't solve the issue. Memory consumption gets bigger though Leaks from instruments doesn't show any leaks.
Is there any way to completely remove those views with their controllers from memory? I want to have the same free memory amount before new controller is created and after it is deleted.
You can override retain and release on any class, to get a better understanding of when the retain count gets higher than you might have expected.
Something like this:
- (id) retain
{
NSLog(#"Retain: Retain count is now %d", self.retainCount+1);
return [super retain];
}
- (void) release
{
NSLog(#"Release: Retain count is now %d", self.retainCount-1);
[super release];
}
When that is said, I think you have to check that your "memory leak" is not just something the system has cached. If you can consistently use more memory by doing the same sequence again and again, then you have a leak.
Problem is solved now, it was UIWebView. It kept some cache and there was no way to clear it. After replacing UIWebView with UIScrollView (it was used to show simple local page) problem is gone.
What is the -(void)viewDidUnload is good for?
Could I not just relase everything in -dealloc? If the view did unload, wouldn't -dealloc be called anyway?
In addition to what has already been indicated, I wanted to elaborate more about logic behind -viewDidUnload.
One of the most important reasons for implementing it is that UIViewController subclasses commonly also contain owning references to various subviews in the view hierarchy. These properties could have been set through IBOutlets when loading from a nib, or programmatically inside -loadView, for instance.
The additional ownership of subviews by the UIViewController means that even when its view is removed from the view hierarchy and released to save memory, through which the subviews are also released by the view, they will not actually be deallocated because the UIViewController itself still contains its own outstanding retaining references to those objects as well. Releasing the UIViewController additional ownership of these objects ensures they will be deallocated as well to free memory.
The objects that you release here are usually recreated and set again when the UIViewController view is re-loaded, either from a Nib or through an implementation of -loadView.
Also note that the UIViewController view property is nil by the time this method is called.
As the documentation says:
It is called during low-memory conditions when the view controller needs to release its view and any objects associated with that view to free up memory.
In the same situation dealloc is not called. This method is only available in OS3 and above. Dealing with the same situation in iPhone OS 2.x was a real pain!
Update July 2015: It should be noted that viewDidUnload was deprecated in iOS 6 because "Views are no longer purged under low-memory conditions and so this method is never called." So, the modern advice is not to worry about it and use dealloc.
This is because you will typically set the #property as "(nonatomic, retain)" and as such the setter that is created for you releases the current object and then retains the argument i.e.
self.property = nil;
...does something along the lines of:
[property release];
property = [nil retain];
Therefore you are killing two birds with one stone: memory management (releasing the existing object) and assigning the pointer to nil (since sending any message to a nil pointer will return nil).
Hope that helps.
Remember that viewDidUnload is a method in the view controller, not in the view. The view's dealloc method will get called when the view unloads, but the view controller's dealloc method may not be called until later.
If you get a low memory warning and your view isn't showing, which will happen for instance about any time you use a UIImagePickerController to let the user take a picture, your view will get unloaded and will need to get reloaded after that.
Conclusion:
View Controllers have a view property. Typically a nib or piece of code adds other views to this view. This happens often inside a -viewDidLoad method, like this:
- (void)viewDidLoad {
[super viewDidLoad];
[self createManyViewsAndAddThemToSelfDotView];
}
in addition, a nib file may create a button and append it to the view controller's view.
On iPhone OS 2.2, when -didReceiveMemoryWarning was invoked from the system, you had to release something to free up memory. You could release the whole view controller's view if that made sense. Or just big memory-consuming contents in it.
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
Now, in the new OS 3.0, there is an -viewDidUnload method, which will be invoked from the system when the view has been unloaded because of low memory (please correct me: when exactly does this get called?)
-viewDidUnload is used to release all objects that were owned both by the view controller itself and the view. The reason: If a view controller holds references to childs of the view, i.e. a button, the referenced child views will not get released, because their retain count is >= 1. After they are released in -viewDidUnload, they can get freed up from memory.
Apple deprecated viewWillUnload, now you shoud use didReceiveMemoryWarning or dealloc to release your objetcs.
In iOS 6, the viewWillUnload and viewDidUnload methods of
UIViewController are now deprecated. If you were using these methods
to release data, use the didReceiveMemoryWarning method instead. You
can also use this method to release references to the view
controller’s view if it is not being used. You would need to test that
the view is not in a window before doing this.
If the view controller is popped from the navigation controller stack and is not retained anywhere else, it will be deallocated, and dealloc will be called instead of viewDidUnload. You should release the views created in loadView in dealloc, but it is not necessary to set the variables to nil, because soon after dealloc is called the variables will no longer exist.
You can release any subviews you hold on to, for example that UIImageView you retained in your loadView method, or better yet the image that was on that UIImageView.