Release for controllers and views - iphone

If I have a set of custom UIViewControllers that I release in a high level application "restart" routine, would a good way to release their views be to set
self.view = nil;
in the dealloc method?

I'm not sure where your views are, but you usually would want to remove them from superview (if they have one)
[someView removeFromSuperview];
if it's retained by something else other than its superview, you'd want to release it
[someView release];
assuming your retainCount is then 0, dealloc will be called (in 99% of the cases, you should never call dealloc yourself)
then yes, you would want to nil it.
someView = nil;
then you can recreate your views or whatever you want to do.

Related

is removeFromSuperview releases the object?

I am using removeFromSuperview for removing a view from its superview. I am also using release after removeFromSuperview on that object, sometimes its work fine but sometimes give bad access.
is removeFromSuperview also call release to the object ?
Yes, removeFromSuperview also releases view.
You need to release your view after you have added it to its superview.
CGRect frame; // let's assume you already have defined frame and superview
UIView *superview;
UIView *subview = [[UIView alloc] initWithFrame:frame];
[superview addSubview:subview];
[subview release];
Or just use autorelease, when you create a view.
UIView *subview = [[[UIView alloc] initWithFrame:frame] autorelease];
[superview addSubview:subview];
In both cases, you don't need to call release after you call removeFromSuperview.
Yes, addSubview calls retain, and removeFromSuperview calls release. So your call to release does not belong there (it probably belongs after you assign the subview, assuming you do not want to hold the object).
The correct answer is "probably". This is an implementation detail that you shouldn't even really be thinking about. If your code needs to work with the subview, then you should be retaining it before you start working on it, and you should be releasing it when you're finished working with it (which may or may not coincide with removing it from it's superview).
I imagine testing would show that removeFromSuperview does release the view, but you cannot depend on this behaviour and should never assume it will happen. Even if it does always happen now it might not in future.
You shouldn't even need to think about memory management at such a low level as this. If you retain the object with retain or copy or alloc or new then you are responsible for counter-acting that with a release at some point in the future.
If you did not do any of these things, then you should not be releasing it. The methods for adding a subview to a view do not contain retain or copy in their name and therefore you are not supposed to release it yourself when you remove it from it's superview.
The view system is very complicated, especially on an iPhone with such a limited amount of RAM and not inadequate storage to use virtual memory. Stick to the rules and you should be fine. Or enable ARC.
Actually removeFromSuperview decreases the retainCount property of the view Object and so as the release.
So,if you do the way Aleksejs said.
UIView *subview = [[UIView alloc] initWithFrame:frame];
[superview addSubview:subview];
[subview release];
subview -> alloc= retainCount = +1 ,
subview -> addSubView = retainCount = +1
subview -> release = retainCount = -1.
subview -> removeFromSuperView = retainCount = -1
(subview removed from memory)

how to release UIVIewController after remove his view

How to release view controller created like this:
VCClass *vc = [[VCClass alloc] initWithNibName:#"VCClass" bundle:nil];
[self.view addSubview:vc.view];
so the view appear, UIViewController is allocated. Now I want to releas it from within VCClass. I call inside VCClass:
[self.view removeFromSuperView];
my question is, where should I release "vc" object attached to removed view. Is there a good way to notify viewcontroller that is can be released while view is released ?
addSubview does a +1 to the retain count, and it's usually a good practice to release as soon as you don't need it, and you're handing it to another pointer. It's like a glass ball, it is passed hand by hand, and if no one is holding, it falls to the ground and breaks.
Example:
UIView *sampleView = [[UIView alloc] init]; // Retain count: 1
[self.view addSubview:sampleView]; // Retain count: 2
[self.view release]; // Retain count: 1
When the removeFromSubview: is called, the object will be released:
[sampleView removeFromSuperView]; // Retain count: 0
That's for memory management.
Answering your question, a safer way to do what you want to do (loading just a part of an ViewController from a nib (I'm assuming you're using a nib, because you used #"VCClass" in the initWithNibName:), is to use it as following:
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"VCClass" owner:self options:nil];
UIView *view = (UIView*)[nib objectAtIndex:0];
This works by loading the NibName into memory, and then stealing the first element (if you only have a UIView inside, then it will pick that, as the top-most element). This is done similarly for UITableViewCells when loading them from nib files. Nib Files are autoreleased, and it makes more sense, since you apparently just care about the view itself, not the controller.
After you remove it, add a call to
[self autorelease];
Views don't know about their view controllers except as a weak reference to a delegate. This is to avoid a circular reference, among other reasons. VCs often have a life outside their views - hence, the viewDidLoad and viewDidUnload messages. For example, throughout the lifetime of a tab-bar application, the VCs for each tab might go through many different view instances while never being deallocated. Therefore, you should avoid having the view release its own view controller.
Often, the class that allocated the VC should be the one to release it. In the code you provided, you have:
VCClass *vc = [[VCClass alloc] initWithNibName:#"VCClass" bundle:nil];
[self.view addSubview:vc.view];
The controller class that the above code is in is probably the place best suited to releasing the VC. You might need to devise a delegate call just for this purpose.
[self.view removeFromSuperView]; should release your said view from the memory. Though be warned that this will not be true if your view has been retained by any other object that is its retain count is more than 1. Also look at the second answer on this thread.
Does UIView's removeFromSuperView method remove the UIView from memory

Release UIViewController if available

Hey,
I'm adding a UIViewcontroller as a subview of my current view. With something like that:
[self.view addSubview:viewcontroller.view];
The user can interact with that added viewcontroller so I can't just release it after I added it's view as my subview, right ?
So I would like to release it the dealloc methode and set it to nil in viewDidUnload when my master viewcontroller gets unloaded, right ?
The problem is, the viewcontoller I add as a subview is not added every time. So the question is, how can I ceck if the viewcontroller was added as subview and if so, release it.
Thx a lot !
Sebastian
You can check it like this:
if(viewController)
{
[viewController release];
viewController=nil;
}
and yes u need to put this in your dealloc method.
If you read correctly your code:
[self.view addSubview:viewcontroller.view];
it is not the controller which is being added as a subview, rather the view it manages.
This is an important point, since it means that the controller itself does not get retained. What is retained is the view.
So you can simply go on releasing your viewController in -dealloc as usual:
-(void)dealloc {
[viewController release]; viewController = nil;
...
}
and in your viewController's dealloc you will need to release the managed view, if you allocated it manually (or wherever it makes sense for your controller to release its view, if necessary).
On the other hand, whenever your superview is deallocated, then also the view you added as a subview will be released (as per Apple spec of addSubview behavior). So nothing to worry about here. Just release the viewController properly (and make that the view controller manages correctly tis own view).
One more note: you should not release your view controller in viewDidUnload.
In some open source code that I used to contribute to, we had a macro called RELEASE_TO_NIL which did exactly this.
#define RELEASE_TO_NIL(obj) if(obj != nil) { [obj release]; obj = nil; }
You would use it like this:
RELEASE_TO_NIL(viewController);
Simple as that.
Just add an tag to viewController.view and test if self.view contains that tag.
UIView *testView = [self.view viewWithTag:yourTag];
if(testView!=nil){
doStuff;
}
According to the Apple docs, a UIViewController instance should manage a view that fills the whole screen. If your view does not fill the screen, you could either subclass UIView to handle delegation or make the superview work as a delegate.
Also, the subviews of a view are contained in an instance of NSArray, do [myView subviews] to return this property. Ask the returned array if it contains the subview in question and you can release accordingly.
But, without knowing more, it does sound like you need to rethink how you're setting all this up.

(iphone) uiimage, view, subviews memory management

I need to release uiimage/view/subviews when I want, and have a few questions regarding proper practice of releasing them.
[imageView removeFromSuperview] would release the imageView and imageView.image?
view = nil; would release its subviews/and associated uiimages recursively? if not, should I implement a recursive function to release a view's subviews?
Thank you
Edit.
I looked at UIView's library reference
addSubview --
This method retains view and sets its
next responder to the receiver, which
is its new superview.
removeFromSuperview --
If the receiver’s superview is not
nil, the superview releases the
receiver. If you plan to reuse a view,
be sure to retain it before calling
this method and release it again later
as appropriate.
still not sure [imageView release] releases uiImage associated with it,
and would I still need recursive releasing of subviews. ie a view's getting dealloced would automatically guarantee it's subviews release?
[imageView removeFromSuperview] would
release the imageView and
imageView.image?
removeSuperView calls release on the view, but you should pay attention to the views retain count. Just because you called removeFromSuperview doesn't mean it's doing what you want.
view = nil; would release its
subviews/and associated uiimages
recursively? if not, should I
implement a recursive function to
release a view's subviews?
No, you probably want to do (depending on how you've managed your subviews during their creation. If the superview was their only reference, they likely have a retain count of 1 and therefore calling release after calling removeFromSuperview will result in an error):
for (UIView* subview in view){
[subview removeFromSuperView];
[subview release]
}
[view release];
EDIT: To answer your final question, no, calling release on a view does not automatically call release on all of its subviews. You have to do it yourself, whether with release or with removeFromSuperview.
When you do [imageView removeFromSuperview], it won't release anything. You need to so [imageView release] afterward. Even so, you still need to put your memory releasing for that view in imageView's dealloc.

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.