My current understanding is that superviews have retains each of their subviews. For a subclass of a UIView, do I need to remove all of my subviews from their superview as part of dealloc? I'm currently just releasing my IBOutlets, removing observed notifications, and clearing up any pesky ivars.
Or is removing and releasing subviews part of a UIView's [super dealloc]?
As a part of the view's dealloc, the subviews are removed automatically. So you don't need to remove them. However, if your view has retained any of its subviews [aside from the automatic retain], you should release them during dealloc.
So for example suppose your view contained the following code:
[header file]
UILabel *myLabel;
#property (nonatomic, retain) UILabel *myLabel;
[implementation file]
someLabel = [[UILabel alloc]initWithFrame: someFrame];
[self addSubview: someLabel];
self.myLabel = someLabel;
[someLabel release]; // now retained twice, once by the property and once as a subview
someButton = [[UIButton alloc]initWithFrame: someOtherFrame];
[self addSubview: someButton];
[someButton release]; // retained once as it is a subview
then your dealloc method would look like this:
- (void) dealloc {
[myLabel release];
[super dealloc];
}
UIView retains its subviews, so it's responsible for releasing them. Your subclass doesn't own those views (unless you explicitly retain them), so you don't need to worry about releasing them.
So it sounds like you're doing the right thing.
Related
I have a UILabel in my class header file defined as :
`#property (nonatomic, retain) UILabel *label1;`
and it exists as instance variable like this:
`UILabel *label1;`
and synthesized in the .m file, however, in viewDidLoad method I do:
`label1 = [UILabel alloc] init] autorelease];`
then I do various things on the label like setting its frame, text color, etc ...
when the view controller is deallocated, the app crashes with this message in console
(Zombies enabled): `[CALayer release] message sent to deallocated instance` ...
The app will not crash when I :
1) remove the autorelease word .. or
2) if i do not release label1 in the dealloc method .. or
3) remove [super dealloc]; from the dealloc method of the view controller.
how can I properly release this UILabel without facing such crash !!
You are doing right.Autorelease and release in dealloc.
But it shouldn't be crash.Because I did the same thing to check.
Could you please check accciendlty may be u release the label some where else.
And releasing in dealloc again.
since you have declared the label as retain. The allocation can be
UILabel *myLabel = [[UILabel alloc] init];
// set all properties of label
self.label1 = myLabel;
[myLabel release];
myLabel = nil;
And in dealloc release your label1.
[label1 release];
this is the way I'm used to and this makes things smoother for me.
the label is released already before dealloc is called. that is because its an autorelease object. your dealloc is trying to release a UIlabel that already been released, an it crashes.. in your question. you can use 1 or 2. if you allocated the object once, then call a release just once. its not because you assign retain to your property in #property directive will add 1 retain count to your object , #property(retain) will not allocate anything, but will tell the compiler how you want your properties treated
strangely enough, when I used self.label1 = [[[UILabel alloc] init]autorelease]; instead of label1 = [[[UILabel alloc] init] autorelease]; solved the problem. the dealloc method remains as is without any change. really weird !!
Do this and u will not use autorelease for label1:
- (void)dealloc
{
if(label1)
{
label1 = nil;
[label1 release];
}
[super dealloc];
}
I dynamically add a subview to another uiview;
in the subview ,click a button to go back by the following method:
[self removeFromSuperView ];
but after manny times added subview and removed it,my app could crash ,the log said it was killed .
I found that calling [self removeFromSuperView] didn't release self. So what's the best methods to releas it?
If you are retaining the UIView on creation (or adding it to an array) the retain count will increase. For example:
// Retain count is 1
UIView *myView = [[UIView alloc] initWithFrame:myFrame];
// Retain count is 2
[myParentView addSubview:myView];
// Retain count is 1 again
[myView removeFromSuperView];
In the above example you can autorelease the view if it is immediately added as a subView or release it in your dealloc if it is an iVar.
EDIT: (other reasons your view could be retained)
// Retain count +1
[myArray addObject:myView];
// Retained in the setter created by the #synthesize directive
#property(nonatomic, retain) UIView *myView;
Anything else that states in the documentation that the property is retained.
You should also be careful of creating objects in the loadView method of a VC, if you do make sure you release them, as they will be created again when the loadView is called. This will happen if you VC's view is unloaded and then reloaded.
u should release at first. counterpart of "alloc" is "release", and counterpart of "addSubview" is "removeFromSuperView":keep those balance.
add view:
UIView *myView = [[UIView alloc] initWithFrame:myFrame];
[myParentView addSubview:myView];
[myView release];
remove view (the view will clear up in memory after removeFromSuperView):
[myView removeFromSuperView];
Looks like you are adding retained view as a subview. Its parent view retains it once again.
So when you cell [self removeFromSuperView]; it gets release message from superView, but still have to be releasd by creator.
Should I release my subviews of UIView in the viewDidUnload when I have references to them as instance variables which retains them? I have build the GUI programmatically. I should do that right? Since both uiview and ivars retain then the objects would have 2 in retain-count, when view receives e.g. memory-warning then the UIView will release the subviews, but they still have +1 in retain count so I have to setself.myIvar = nil; In the viewDidUnload?
Thanks for your time.
You actually can release all retained subviews in viewDidUnload. But I used to do it in another way:
-(void) viewDidLoad {
someInstanceView1 = [[UIView alloc] init];
[self.view addSubview: someInstanceView1];
[someInstanceView1 release];
someInstanceView2 = [[UIView alloc] init];
[self.view addSubview: someInstanceView2];
[someInstanceView2 release];
//etc...
//you have a references to someInstanceView1 and someInstanceView2 with retained counts 1
}
In this case even if memory warning will arise, the view controller will remove all it's view subviews. And then call viewDidLoad again. So there would be no leaks and you don't need to care about releasing that ivars at all cause the only owner (it has the strong reference to the views) is the view controller's view and it will release them automatically.
In my viewbased application i loaded oneview as mainview and another view as subview of mainview. Its work well the code snippet is ,
In mainviewcontroller,
IBOutlet UIView *subView;
#property(nonatomic,retain) UIView *subView;
#synthesize subView;
[subView release];
//add subview
[self.view addSubview:subView];
//removefromsubview
[subView removeFromSuperview];
This code works fine.....
I dont want to create subview in mainviewcontroller, so i created a new UIView class and its named as subView, now i deleted all declarations of subView from mainviewcontroller and just import subView class in mainviewcontroller. And using this [self.view addSubview:subView];
This things not work great. Can anyone help me ... How can i interact a separate UIView class with UIViewcontroller.One more thing is that UIView class have labels and textboxes can i set values from UIViewController to UIView labels and textboxes ......
Is it possible ?
Thanks in advance.......Sorry for my bad english
You have a sub-class called Subview which is declared as a UIView, i.e.
#interface Subview : UIView {
UILabel *foo;
}
#property (nonatomic, retain) UILabel *foo;
#end
Now you want to use this sub-class inside of your main UIView, which you had from the start. There are a few things you need to do.
#import the Subview in your header file, and add an instance of it to your class.
#import "Subview.h"
and inside of your #interface's {}'s,
Subview *mySubview;
In the viewDidLoad class for your main view controller, around the bottom, add something like:
mySubview = [[Subview alloc] init];
[self.view addSubview:mySubview];
[mySubview release];
First line will allocate a new "Subview" for you, second line will add this to your view so you get the stuff it has, and third line will release it. It's okay to release it here, because "self.view" will now be responsible for it, so it won't vanish.
Lastly you need to set the view up in the init method for Subview. In Subview.m, do something like:
- (id)init
{
if (self = [super init]) {
foo = [[UILabel alloc] init];
foo.text = #"Hello!";
[self addSubview:foo];
}
return self;
}
And I think that should take care of it. You also want to release foo in -dealloc for Subview but you probably know how to do that stuff already.
I read somewhere that in a programmatically created view in a UIViewController, not using Interface Builder, -viewDidLoad and -viewDidUnload should not be used. Is this right? Why? Where would I release subviews that I have retaining properties of? Or should I just not use properties for them?
EDIT: Read my comments on Rob Napier's answer.
Create your subviews in -viewDidLoad. If you need ivars for them then only assign their values. The reference is hold by adding the views as subviews to you main view.
Then when your view is unloaded you should set your ivars to nil, because the object have been released since your view was removed and released.
So in your header
#interface MyViewController : UIViewController {
IBOutlet UIView *someSubview; // assigned
}
#property (nonatomic, assign) IBOutlet UIView someSubview;
#end
And in your implementation
#implementation MyViewController
//... some important stuff
- (void)viewDidLoad;
{
[super viewDidLoad];
someSubview = [[UIView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:someSubview]; // retains someSubview
[someSubview release]; // we don't hold it
}
- (void)viewDidUnload;
{
[super viewDidUnload];
someSubview = nil; // set the pointer to nil because someSubview has been released
}
//... more important stuff
#end
If you wish you can also not release someSubview in -viewDidLoad, but then you have to release it in -viewDidUnload AND -dealloc since (if I remember right) -viewDidUnload isn't called before -dealloc. But this isn't necessary if you don't retain someSubview.
the strange thing here is that an UIViewController not loaded from a NIB file is not notified about its view unloading (and so its viewDidUnload method is not called) unless you offer a base implementation of the loadView method, such as:
- (void)loadView {
self.view = [[[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds] autorelease];
[self.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
}
- (void)viewDidLoad {
[super viewDidLoad];
// create views...
}
- (void)viewDidUnload {
// destroy views...
[super viewDidUnload];
}
this only happens to base UIViewController, an UITableViewController for example don't need to be fixed with this workaroud.
So Robs is right.