explanation for Apple's advise to nil objects in "viewDidUnload"? - iphone

I would be interested in anyone who can provide a little more information regarding Apple's recommendation below (found in the Core Data tutorial) re nil'ing objects in "viewDidUnload". For example:
why this is important? different between releasing an nil'ing?
is this best practice / I haven't been doing this nor seeing this I don't think in some iPhone example code I've looked at?
Code:
// The implementation of viewDidUnload should relinquish ownership
// of anything created in viewDidLoad that can be recreated.
- (void)viewDidUnload {
self.eventsArray = nil;
self.locationManager = nil;
self.addButton = nil;
}
- (void)dealloc {
[managedObjectContext release];
[eventsArray release];
[locationManager release];
[addButton release];
[super dealloc];
}

Setting the properties to nil will release them as well (assuming the setter method releases the old value as it should do).
Additionally, setting the properties to nil means that any messages that might end up getting sent to them afterwards will be swallowed by nil and ignored. In the situation where they were simply released, the object might get deallocated and overwritten in memory, but they could still have messages sent to them (now being sent to whatever overwrote them in memory), likely causing a crash, an exception, or other unexpected behaviour.

The viewDidUnload method will get called when we have a low memory situation. In low memory situations, the xibs will be released from memory to free memory for the app. But that won't be effective enough if we are still retaining the nib objects in our app. So when we set our nib objects to nil in viewDidUnload we are helping to free more memory.

Related

Getting EXC_BAD_ACCESS on a method call

This is really weird in my perspective. I've never seen anything like it. I put all my releases in a method called releaseMethod. Then in my dealloc and didReceiveMemoryWarning, I have [self releaseMethod]; I do this to be more object orienteted and save code because I have a lot of releases. But, occasionally (2 out of 5 times, give or take), I get EXC_BAD_ACCESS on the releaseMethod call in dealloc. The code is below. I didn't know it was possible to have a method call get bad access. I understand memory management and there is no memory involved in calling a method, right?
Thanks in advance.
- (void)dealloc {
[super dealloc];
[self releaseMethod];
}
Put your [super dealloc] at the end of the dealloc so you can first cleanup things in your class before cleaning up things in the superclass (which you might depend on).
If you send the message release to an object that has already been deallocated, this is the message you will get. Check that you aren't overreleasing something in releaseMethod. Remember, when an object is deallocated, it will release objects that it is retaining.
You should also put [self releaseMethod] before you call [super dealloc].

When does (void)dealloc get called in an AppDelegate?

I understand that instance variables are released in dealloc (as shown below), but when exactly is it called? Are all instance variables released upon app close, or is there an accepted way for them to be deallocated individually as they become unneeded?
- (void)dealloc {
[fred release];
[wilma release];
[barney release];
[betty release];
[super dealloc];
}
Like any other object, the app delegate will be deallocated when no other object has retained it. It's pretty unusual to have an app delegate that doesn't stick around until the app terminates, and as others have pointed out, the app may not bother to release and deallocate anything just before it exits.
I think it's a safe bet that the app delegate would be deallocated if no object other than the app had retained it and you gave the application a new delegate. Aside from that unusual situation, the app delegate's -dealloc method probably doesn't get called very often at all. However, that doesn't mean that you shouldn't implement it correctly -- it's expected behavior, and things could easily change in a future iOS release.

iOS SDK - dealloc implementation - Release child views first?

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.

Use of viewDidUnoad

What is the use of viewDidUnload and didReceiveMemoryWarning methods?
When they actually get called?
what are the difference between dealloc, viewDidUnload and didrecievedmemorywarning?
viewDidUnload: It is called when viewcontroller recieves the low memory warning.
dealloc: It is called when the object/viewController is released.
didRecieveMemorywarning: Also called when the controller recieves the low memory warning.
So Whats the difference between viewDidUnload and didrecieveemoryWarning?
viewDidUnload is the place where you need to clean up the UI related things i.e., outlets.
didRecieveMemoryWarning is a place where you need to clean up the other objects which are holding memory and not used frequently.
viewDidUnload is supposed to undo what viewDidLoad does, just like dealloc is supposed to free up whatever resources init created. So:
-(id)init {
if (self == [super init]) {
foo = [[Foo alloc] init];
}
return self;
}
-(void)dealloc {
[foo release];
[super dealloc];
}
-(void)viewDidLoad {
[super viewDidLoad];
bar = [[Bar alloc] init];
}
-(void)viewDidUnload {
[bar release];
[super viewDidUnload];
}
didReceiveMemoryWarning is there so you can free up any unnecessary memory. Perhaps you cache images. That's nice to have, for a snappy UI, but when memory's tight you can release that memory and your application's performance can degrade gracefully.
It's a good idea to start with Apple's documentation, as there is a lot there about this subject.
viewDidUnload is called when a UIViewController subclasses unloaded it's view. The view is then released, and all IBOutlets are disconnected. The method is usually fired when a viewController is popped, or when it recieves a memory warning.
didRecieveMemorywarning is called when the OS sends a memory warning. This happens when the device is low on memory. You should try a release as much data as possible here, to free up memory. Caches, data that is not needed at the moment, etc.
If you don't free up memory, your app will be killed at a certain point to free up memory for the OS.
Dealloc is called when the instance is deallocated.

How to implement didReceiveMemoryWarning?

I have developed a simple location aware iPhone application which is functionally working very well to our expectations except in the low memory condition of the phone .
In low memory condition of the phone my app just crashes and If I increases the phone memory by freeing up some space it again start working well without any crash .
when I did some googling on the problem I found that in the low memory conditions the OS will send didReceiveMemoryWarning to all the controllers in the current hierarchy so that each one of them should implement didReceiveMemoryWarning method and also set iboutlet to nil for the view that is currently not visible .
I have also read somewhere that if the view for that controller is not visible the method setView with nil parameter will be called and if there are some outlet variables attached to view there will be problem in removing them.
So with all these fundas what is the best to handle low level memory condition raised by the Iphone by implementing the didReceiveMemoryWarning and viewDidUnload methods.
Please give a proper example or link if possible for the solution of the above problem .
thanks.
One example i am posting...which i have copied from somwhere... it might give you some idea...
- (void)didReceiveMemoryWarning {
// Release anything that's not essential, such as cached data (meaning
// instance variables, and what else...?)
// Obviously can't access local variables such as defined in method
// loadView, so can't release them here We can set some instance variables
// as nil, rather than call the release method on them, if we have defined
// setters that retain nil and release their old values (such as through use
// of #synthesize). This can be a better approach than using the release
// method, because this prevents a variable from pointing to random remnant
// data. Note in contrast, that setting a variable directly (using "=" and
// not using the setter), would result in a memory leak.
self.myStringB = nil;
self.myStringD = nil;
[myStringA release];// No setter defined - must release it this way
[myStringC release];// No setter defined - must release it this way
/* 3. MUST CONFIRM: NOT necessary to release outlets here - See override of
setView instead.
self.labelA = nil;
self.imageViewA = nil;
self.subViewA = nil;
*/
// Releases the view if it doesn't have a superview
[super didReceiveMemoryWarning];
}
Memory warnings are a signal to you that you should dispose of any resources which aren't absolutely critical. Most of your controllers will be hanging onto data caches, intermediary data, or other bits and pieces, often to save recalculation. When they receive memory warnings, they should begin flushing anything they don't immediately need in order to operate.
How you determine what is "critical" depends entirely on your application's design. An OpenGL game, for example, may determine that textures currently on-screen are valuable and flush textures which aren't visible, or level data which is outside the bounds of the current play area. An application with extensive session logs (like an IRC client) may flush them out of memory and onto disk.
As you observed, the warning is sent to each controller in your hierarchy, so each piece needs to determine individually what data constitutes "critical for operation" and what constitutes "expendable". If you've optimized them all and are still getting out of memory warnings, it's unfortunately time to revisit your core application design, because you're exceeding the limits of the hardware.
On iOS 5 and earlier.
When controller receive a memory warning, didReceiveMemoryWarning will be called. At that time, if controller's view is not in the view hierarchy, the view will be set to nil and viewDidUnload will automaticly invoked. So the things we must do in viewDidUnload is releasing sub view created in viewDidLoad or created from Nib. Like this:
- (void)viewDidUnload
{
self.subView = nil;
self.subViewFromNib = nil;
}
- (void)didReceiveMemoryWarning
{
self.someDataCanBeRecreatedEasily = nil;
[super didReceiveMemoryWarning];
}
On iOS6.
The controller doesn't automaticly release the view when receive a memory warning. So the viewDidUnload never be called.
But we still need to release our view (including sub view) when a memry warning happens.
Like this.
- (void)didReceiveMemoryWarning
{
if ([self isViewLoaded] && [self.view window] == nil) {
self.view = nil;
self.subView = nil;
self.subViewFromNib = nil;
}
self.someDataCanBeRecreatedEasily = nil;
[super didReceiveMemoryWarning];
}
Note that we don't call [self view] before we know the view is loaded. cause the this method will automaticly load view if the view is not loaded.
Note that we can release the view just when the view is not added to a window.
It's up to you to decide what to do in didReceiveMemoryWarning. The OS is telling you that memory is low, and you need to free up as much as you can as soon as you can. The idea is that you should free any cached data, unload views that aren't visible, etc. The details are application specific.
You could also release memory in didReceiveMemoryWarning, that you allocated for static variables in your classes. Because once the memory for static variables is allocated it'll not be freed during the application runs.
To my surprise, only a few apps in the official iPhone samples implement didReciveMemoryWarning. You can use the iPhoneCoreDataRecipes example as an reference.
Some samples (e.g. TableViewSuite) even do something else ;-)