how much to release in viewDidUnload - objective-c

The Apple template provides this comment in the viewDidUnload:
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
So I typically set IB Outlets to nil in viewDidUnload then release them in dealloc. The question is, all my other retained ivar objects, some of which are views that were added programmatically, while others are data models, should they also be dealt with in these two methods? If not, why not?
from this answer here i gather that only view-related objects should go in viewDidUnload as =nil statements, which should probably include non-IB Outlet retained views, correct? Then, all other objects, included data models, should go in dealloc as release statements. Is this the normal practice?

viewDidUnload is called as a result of a low memory condition to unload the view for a view controller that is not currently visible. At this point the view object of the view controller has been released which means all the objects that are subviews of viewController.view have been released, but they are not deallocated if you are retaining them in your ivars.
You should release any object that will be recreated when the view is loaded again or things you can easily recreate as needed. The next time the view is used the view will be recreated either from the NIB or by calling loadView so all those things you release will be recreated.
When your view comes from a NIB all the view objects specified in the NIB are created and added as subviews of the view controller's view. Any ivars with IBOutlets are also connected to those subviews so that you also "own" those objects (you have a retain on them). You need to release those ivars so that they will actually get dealloc'd.
When your view is created programatically in loadView you should also release those object retained by your ivars that will be recreated in loadView the next time the view loads.
Same for anything you create in viewDidLoad (or viewWillAppear or elsewhere), such as data models, if you can recreate it "easily" later when the view loads again or when the object is needed then it should be released in viewDidLoad to reduce memory usage. Actually for non-view items, like a data model, I would release it in didReceiveMemoryWarning instead.
Assigning nil to a retained property using the setter causes a release to be sent to them, when you write self.myOutlet = nil you are invoking the setter method which is implemented something like this:
-(void)setMyOutlet:(id)newObject
{
[newObject retain]; // does nothing if newObject is nil
[myOutlet release];
myOutlet = newObject;
}

Related

Why do we bother setting so many things to nil when a view is Unloaded?

-(void)viewDidUnload
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:LASTUPDATEDLOCATION object:nil];
[self setHeaderViewofWholeTable:nil];
[self setFooterViewofWholeTable:nil];
[self setHeaderActivityIndicator:nil];
[self setFooterActivityIndicator:nil];
[self setLastUpdated:nil];
[self setLblPullDowntoRefresh:nil];
[self setRefreshArrow:nil];
[self setContainerForFormerHeader:nil];
[self setFooterContainer:nil];
[super viewDidUnload];
}
I thought viewDidLoad is called the view itself goes nil. When we set the view to nil, wouldn't all those things automatically become nil?
What am I misunderstanding?
Before ARC you needed to manually release objects that you allocated. Setting a property that is marked retain to nil does the releasing. This is no longer necessary when you use the Automatic Reference Counting (ARC) feature, which is on by default in the compiler that comes with recent versions of Xcode.
Good news. As of iOS 6, viewDidUnload has been deprecated. In iOS 5 and earlier, when memory was low there was a chance that your view might have been unloaded (and to make sure there were no memory leaks, you released IBOutlets in this method). But this is no longer called in iOS 6, and thus, no longer a requirement.
Now if there is a issue with memory, your view controller can override:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
Some of the other answers cover some of this but there is more to this. A view controller will have its viewDidLoad method called. Typically this results in IBOutlets being retained and possibly lots of other views and objects being allocated and retained. If all goes well, eventually the view controller is deallocated and all of those retained objects need to be released.
That's the simple, happy path. Under low memory conditions, in iOS 5 and earlier, it is possible that a view controller's view will be unloaded. The viewDidUnload method was a chance for you to clean up all of the other objects that were retained as part of the viewDidLoad process. And here's the main reason - at some point, viewDidLoad may be called again to redisplay the view controller's view.
Most people write their viewDidLoad method like it will only ever be called once. And this is OK if the viewDidUnload method properly clears up objects. If it doesn't, the next call to viewDidLoad will result in a bunch of memory leaks.
ARC pretty much eliminated the issue with the memory leaks if you didn't clean things up properly in viewDidUnload. But viewDidUnload was still helpful for cleaning up memory when needed.
As was mentioned, as of iOS 6, a view controller's view in never unloaded in low memory conditions and the viewDidUnload (and viewWillUnload) methods have been deprecated.
If your app still supports iOS 5 along with iOS 6, you still need to make proper use of viewDidUnload. But if you want to free up memory when needed, use didReceiveMemoryWarning.
We set so many things to nil to free up as much memory we can and reduce processor strain and increase battery life, not all objects automatically remove themselves from the queue.

Interface Builder sets control outlets to nil -- why?

Using xcode 4.2 for iPhone app, without ARC ---
When I create an outlet using the interface builder xcode adds two lines of code to my viewController. One in viewDidUnload: -- [self setMyOutlet:nil] and second in dealloc -- [myOutlet release].
I understand the latter (the release). But why set the outlet to nil in viewDidUnload. Doesn't viewDidUnload get called before dealloc and won't setting the outlet to nil negate the release operation in dealloc? Setting to nil makes sense I would think for building a Mac application which is using garbage collection -- but it doesn't make sense for an iPhone app.
Why does the interface builder do this? Should I delete the lines which set the outlets to nil?
viewDidUnload may be called and may be not called. It depends on the current memory usage. dealloc is a place where you should clean all your properties (like arrays, custom objects). In viewDidUnload you clean views and perhaps objects created to support the view. viewDidUnload mean that your view is unloaded (but not whole view controller) and it may be created and loaded again (in viewDidLoad, of course) in the future.
Why to nil - Objective-C Difference between setting nil and
releasing
Understanding How Views Are Loaded and
Unloaded
viewDidUnload is not called everytime before a dealloc, see what the apple docs say..
When a low-memory condition occurs and the current view controller’s
views are not needed, the system may opt to remove those views from
memory. This method is called after the view controller’s view has
been released and is your chance to perform any final cleanup. If your
view controller stores separate references to the view or its
subviews, you should use this method to release those references. You
can also use this method to remove references to any objects that you
created to support the view but that are no longer needed now that the
view is gone. You should not use this method to release user data or
any other information that cannot be easily recreated.
so the idea behind it is too release any unwanted objects which can be created easily.
Now coming to the part where it sets the properties to nil.. it does so because this way you release all the memory and set the objects to nil (thus bringing your down your memory usage) and after this if a dealloc is called your app will not crash as in objective-c you can send release messages to nil objects..
I would advise you to read the apple ViewController Programming Guide , it will clear a lot of your questions.... hoping this clears some of the air.. :D

What is the difference between dealloc and viewdidunload?

When should I release all the memory I allocated in my program?
Because I only have a viewDidLoad method where I do my business. Should I leave dealloc empty and cleanup only in viewDidUnload?
'dealloc' is used when the object is ready to be freed (i.e., when retain count of the object becomes 0). And viewDidUnload is called when the view is unloaded, but it may not be freed immediately as the reference of the UIViewController is still stored by some other objects.
my personal preference is, for ojbects created by 'init', they are freed by 'dealloc', for objects created by 'viewDidLoad', they are freed by 'viewDidUnload'.
As the documentation of -viewDidUnload 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. Because view
controllers often store references to
views and other view-related objects,
you should use this method to
relinquish ownership in those objects
so that the memory for them can be
reclaimed. You should do this only for
objects that you can easily recreate
later, either in your viewDidLoad
method or from other parts of your
application. You should not use this
method to release user data or any
other information that cannot be
easily recreated.
Typically, a view controller stores
references to objects using an outlet,
which is a variable or property that
includes the IBOutlet keyword and is
configured using Interface Builder. A
view controller may also store
pointers to objects that it creates
programmatically, such as in the
viewDidLoad method. The preferred way
to relinquish ownership of any object
(including those in outlets) is to use
the corresponding accessor method to
set the value of the object to nil.
However, if you do not have an
accessor method for a given object,
you may have to release the object
explicitly.
There is no mention -viewDidUnload will call in -dealloc, you shouldn't rely on it.

Memory management help for Objective-C

I'm studying memory managment in UIviewController, i'm a little confused, the important points to remember are:
viewDidLoad is called every time the view is shown, here I alloc variables of any kind.
viewDidUnload is called in case of low memory, I set all the property to nil.
dealloc, I release all property.
Is it all right?
Also, if I don't link a label to a IBOutlet, have I a memory leak or the system dealloc it anyway?
No. -viewDidLoad is called when the controller loads its view, not every time the view is displayed. Perhaps you're thinking of -viewWillAppear. Otherwise, your points are about right.
If you don't connect something to an outlet, the outlet will simply remain nil -- there's no leak. The label will generally be retained by its enclosing view, and will be released when the rest of the view hierarchy is released.

Memory management in interface builder

If I put a label in Interface Builder, and don't connect it with an IBOutlet, do I have a memory leak? Or does the system call dealloc itself?
No, you won't have a leak. Without an IBOutlet, you are never directly calling retain on the object. Therefore the only thing that will be retaining the object is the view that the label is a subview of, because when you add a subview to a view, it calls retain. When the parent view is dealloced, it will call release on all of its subviews, which will dealloc the label.