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.
Related
Random crashes occur in my iphone project, see two call stacks, all in web core, all crash after UIWebView deallocate.
See crash 1, seems web core can't close it completely, is it blocked by other running threads?
See crash 2, why it is still dealing with some issues even if UIWebView has been released?
Any idea or discussion will be appreciated, thanks in advance.
Crash 2 has higher reproducible rate than crash 1, scan WebCore source code, it seems be manifest cache has been deleted (who did it?) when try to access it.
My guess is that you're setting some object (probably your view controller) as the delegate of your webView, either via Interface Builder, or via code that looks something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.webView.delegate = self;
}
- (void)dealloc
{
[self.webView release];
[super dealloc];
}
This code has a serious bug that's not immediately obvious if you don't know what to look for. Can you spot it?
When the controller gets dealloc'd it releases the webView, but this doesn't necessarily mean the web view no longer exists. It may still be retained by some code down inside its internal implementation, and it may still be loading content.
When it finishes loading, the web view will call a method like webViewDidFinishLoad: on its delegate. The problem is, your view controller was the delegate, and your view controller no longer exists. The section of memory where your view controller used to live has been reclaimed by the operating system, and is no longer accessible to your application process. The web view doesn't know this though. It still has a reference to that memory address in its delegate property. So it tries to call a delegate method on that object, and whoops... EXC_BAD_ACCESS.
Crashes like this appear to be random since they depend on what your app is doing in the background at the time. This makes them tricky to diagnose. Fortunately they're easy to solve. Simply set the object's delegate to nil before you release it your dealloc statement, like this:
- (void)dealloc
{
self.webView.delegate = nil;
[self.webView release];
[super dealloc];
}
By setting the web view's delegate to nil before you release it, you guarantee that the web view won't try to call delegate methods on your object after it's been deallocated.
If you're using ARC, your class may not have a dealloc method. That's normally fine, but in a case like this you should go ahead and add one. You don't want to call release if you're using ARC, but you should still add a dealloc method and set the delegate property to nil.
To avoid similar crashes in the future, apply this best practice any time you set your object as the delegate of another object.
Before releasing the webview, try to reset the delegate an stop loading.
[webView stopLoading];
webView.delegate = nil;
[webView release];
webView = nil;
Is it safe to do something like:
- (void) viewDidUnload {
[self cleanup] ;
[super viewDidUnload];
}
Because I hear things such as "self" may not even exist in a non-corrupt form when the view is unloading, hence it may be unsafe. Is it safe?
It's totally safe. viewDidUnload gets called in low memory situations when the view controller has temporarily deallocated the view to conserve memory. You just don't want to do anything in there that would access your controller's view property, as that would cause the controller to lazy-load the view again. Other than that, calling methods on self in viewDidLoad is totally safe.
You may be thinking of the dealloc method. I've seen people assert that you shouldn't call methods on self in your init or dealloc methods because your object may be in a partially initialized/released state. I guess the fear is that someone will try to modify or override the method you're calling without realizing that it's being called on a partially-formed object. This risk is increased if you don't set your released properties to nil in dealloc.
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].
I have a property defined as:
#property(nonatomic, retain) UITableView *settingsTableView;
Then in my viewDidLoad method I have:
self.settingsTableView = [[[UITableView alloc] initWithFrame:tableFrame style:UITableViewStyleGrouped] autorelease];
[self.view addSubview:self.settingsTableView];
[self.settingsTableView release];
Then in the dealloc method of the view controller I have:
[settingsTableView release];
When I attempt to do the release from within the dealloc I am getting a "message sent to deallocated instance". I am starting to second guess myself, anybody see anything stupid in what I've done?
Really appreciate the help on this one!
you're calling release on an object you've already autoreleased. Just get rid of the line
[self.settingsTableView release];
and you should be good.
Note that you should keep the release in the dealloc method, since the property calls retain for you, but not release.
Two things. First, you're over-releasing the table view in the first place: the autorelease call negates the need for a manual release afterwards.
Also, in general, what you release in -dealloc are things that you created in -init, -initWithCoder:, or whatever, not loadView or -viewDidLoad. In this case, the method you're looking for is -viewDidUnload; you just have to set self.settingsTableView to nil in that method, and the property setter will handle releasing it if necessary.
Here is the change you need to make.
self.settingsTableView = [[[UITableView alloc] initWithFrame:tableFrame style:UITableViewStyleGrouped] autorelease];
[self.view addSubview:self.settingsTableView];
[self.settingsTableView release];
//^^^ This line is bad no need to release this value until dealloc
//if it is defined as retain or copy
Seems obvious. You have already released with
[self.settingsTableView release];
So why release it again in the dealloc?
I believe the problem is related to your use of autorelease when you are allocating and initializing the UITableView.
You also might have a problem with releasing the settingsTableView right after you use it, vs. in the dealloc method. Anytime you alloc/init an object, you should only release it once.
If you use autorelease, the rules are a little different, so I'd recommend reading up on that again. Also, when you pass objects that you've created off to other things, they may take complete or shared ownership of the object by retaining it, meaning that you may or may not need to release it yourself anymore. The documentation for that should be on the method you're calling (like addSubView).
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.