UIButton - should we release or not? - iphone

I want to add a button on a view dynamically. Here is the code.
UIButton *x=[UIButton buttonWithType:UIButtonTypeRoundedRect];
Here, I have not used "alloc" function.
The questions for this statements are as follow.
If we are using imageview for the same situation, we have to create an temp imageview add to your current view and release it. What to do for button?
How are buttons allocated and de-allocated?
If buttons are allocated? How it's memory is been managed?
Now when I use [x release]; - is it right or wrong?

No alloc/init or new so it will be autoreleased when it is no longer needed. When you add it to the UIView the count is increase and retained by the view, then also released when the view is released.

You do not need to call release in this case. Since you are using a convenience constructor, the object that is returned is an autoreleased object.
If you use an alloc / init form, you are responsible for releasing the object.

UIButton *x=[UIButton buttonWithType:UIButtonTypeRoundedRect];
using this method u cant relese the button
instead of use
UIButton *x = [[UIButton alloc]init];
and then release

Related

How to release subviews

In my iPhone/iPad app,
I am adding one subview to my main view.
This subview has one imageview and button.
When to release them ?
My code is here,
customAlertView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 600)];
UIImageView *imgv=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"celebration.png"]];
UIButton *btnOK=[UIButton buttonWithType:UIButtonTypeCustom];
[btnOK setTitle:#"OK" forState:UIControlStateNormal];
[btnOK addTarget:self action:#selector(alertOKClicked) forControlEvents:UIControlEventTouchUpInside];
[customAlertView addSubview:btnOK];
[customAlertView addSubview:imgv];
[self.view addSubview:customAlertView];
[imgv release];
[btnOK release];
In one another method I am writing the code.
[customAlertView removeFromSuperview];
My confusion is imageview and button is there If
I release the customalertview here will it releases its subviews automatically.
If yes then no problem.
If NO how to release it
as I have done here released the objects immediately after adding subviews.
It will cause my OK button Unworthy. And will not affect the button click.
So, On removing from superview should I write.
[[customalertview subviews] release];
Your code is correct.
You release them after you've added them to the alert view, as the alert view takes care of retaining them. When you call removeFromSuperview, it'll get released automatically.
I think the points you are missing, based on your comments on the existing answers, are the following:
A view retains its subviews - so if you create a new view object, and add it as a subview to something else, you can then safely release it, unless you'd like to keep a reference around for it yourself.
When a view is removed from its superview, it is released. So if there are no more objects retaining it, it will be deallocated.
When a view is deallocated, it will automatically release all of its subviews, and so on down the tree.
Enable ARC as soon as you are able to.
You are doing it the right way. The customalertview will releases its subviews automatically.
Your object will be released when the release count go to 0, that means in the theory, and if you are coding well, that this object does not have any reference to it anymore.
While you maintain your custom alertView in your view, you have an object retaining your things, so the release count will not be 0 until you remove the customAlertView, because you have added they to the customAlertView, and when you remove the alert, the alert will be released, and all the things that it is retaining will be released too.
Hope it help you to understand how things work.
If you want to know more about memory management you can take a look at apple documentation here
EDIT:
I forgot to mention that you will need to release your custom alert too after you remove it.
If you do not understand the memory management you also can take a look at: http://cocoadevcentral.com/d/learn_objectivec/ section 7

When to release dynamically created objects

In my iPad App,
I have one custom class inherited from UIButton.
I am adding the buttons on my main view dynamically using for loop.
This button has also has label.
My problem is when to release the Custom Class's Objects.
for(NSMutableDictionary *dict in Categories)
{
Category *category=[[Category alloc] initWithName:[dict valueForKey:#"category_name"] identity:[[dict valueForKey:#"category_id"] intValue] imageName:nil];
category.lblimagesCount=[[UILabel alloc] initWithFrame:CGRectMake(category.frame.size.width-31, category.frame.origin.y-42, 26, 26)];
[category addSubview:category.lblimagesCount];
[self.viewHeader addSubview:category];
[category release];
category=nil;
}
How to avoid memory leaks.
Especially for
1. labels
2. Category class.
Where to write release ?
i. Category class(UIButton) has its dealloc method but it is never called.
ii. As I am releasing it immediately after adding it to the subview , Will it affect my button click.
iii. When should I release the labels.
Very confused about the memory management.
I'll answer your questions:
i. Category class(UIButton) has its dealloc method but it is never called.
Because its not totally released, see question ii.
ii. As I am releasing it immediately after adding it to the subview , Will it affect my button click.
No, because your subview is now the owner of the button, when you add it to the subview, both you and the subview are owners, when you release, the button now is owned by the subView.
iii. When should I release the labels.
As soon as you add then to the subview, for the same reason as the question ii.
I'll be happy to clarify if you dont understand it.

Creating a button programmatically

I have seen 2 ways to create button.
UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(10, 220, 150, 30)];
and
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
The first case is the normal way to create a button object. I have allocated and initialised a button instance and I have to release that. I am really confused about the second way. I have some questions regarding this.
Is a button instance created in this case?
What is the retain count of this button?
Should I release this button?
Hope this helps:
Yes button instance is created.
Retain count will be how do you add/retain.
You don't need to release button if you have not created it by alloc.
Is a button instance created in this case?
Yes, an instance is created.
What is the retain count of this button?
The retain count is probably one, otherwise the lifecycle would get rid of it.
Should I release this button?
No, you shouldn't the object is autoreleased.
From: http://cocoadevcentral.com/d/learn_objectivec/
On local memory management:
There's only one rule: if you create an object with alloc or copy, send it a release or autorelease message at the end of the function. If you create an object any other way, do nothing.
Yes a local instance is created
1, but will be 0 when the function ends
No, the object will be marked for release when the function ends provided you don't call retain on it.
1.)Yes the button instance will be created whether you allocate it or by using factory method.In both the cases button instance will be created
2.)The retain count will be 1 for the current run loop/cycle,Then on the next loop, the object will be auto released. Thus the retainCount will be 0. (Note: NSLogging a retainCount of 0 will crash the app)
3.)No you don't have to release the button created with factory methods,They are released automatically .

when are objects released

I believe I have to release an object if I created it with the keywords init, alloc, copy, or move I believe. I may create objects with code that don't use this keywords so I guess I don't have to release them right? so take for instance this code:
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Hello" forState:UIControlStateNormal];
button.frame = CGRectMake(40.0, 200.0, 170.0, 40.0);
[self.view addSubview:button];
since I did not use any of those keywords in my code I should not release it right? so when is that object being released? I am little confused with the memory managment stuff.
The only object you created here is the UIButton, and you used the buttonWithType class method. That is returning you autoreleased object, so you don't have to release it.
Keep in mind though that if you were to need this button at a later time you would need to retain it and eventually release it. Because you add this button to a view, the view retains a copy in this case so again you don't need to worry about it.
If you're running XCode 4 I recommend running the 'analyze' mode to run quick basic check for memory leaks... that looks fine (your code).
You are absolutely correct in that you don't have to explicitly release anything that you don't take ownership of via alloc, copy, new, or retain.
In this case, you've created the button via a convenience method (buttonWithType:). This returns an autoreleased UIButton object. This is released automatically when the autorelease pool is flushed at the end of the run loop.
There's nothing for you to worry about here. Let the runtime take care of it.
There is an NSAutoreleasePool that manages the memory for you. You were correct about alloc and copy (alloc and init are usually together) but not move. Another one that returns a retained object is methods prefixed with new ex. +(id)new;. An auto release pool is required for each thread to manage memory for each event loop.
An example of how a button implementation may look
-(id)buttonWithType:(UIButtonType)type
{
UIButton *button = [[[UIButton alloc] initSecretlyWithType:type] autorelease];
//Customize button if needed
return button;
}
See Using Autorelease Pools for more details.

iPhone Memory Management and Releasing

Here's a common practice I see often (including from a very popular iPhone developer book)
In the .h file:
#interface SomeViewController : UIViewController
{
UIImageView *imgView;
}
Somewhere in the .m file:
imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
applicationFrame]];
[imgView setImage:[UIImage imageNamed:#"someimage.png"]];
[self addSubview:imgView];
[imgView release];
And later, we see this...
- (void) dealloc
{
[imgView release];
[super dealloc];
}
Since imgView has a matching alloc and release, is the release of imgView in dealloc necessary?
Where is the imgView retained by the addSubview call accounted for?
The code is incorrect. You'll end up releasing imgView after it's been deallocated.
In your .m file, you:
alloc it --> you own it
add it as a subview --> you and the UIView owns it
release it --> you don't own it
Then in dealloc, you release imgView even though, as we established at step 3 above, you don't own it. When you call [super dealloc], the view will release all of its subviews, and I imagine you'll get an exception.
If you want to keep an ivar of imgView, I suggest not calling release after you add it as a subview, and keep your dealloc the same. That way, even if imgView is at some point removed from the view hierarchy, you'll still have a valid reference to it.
The code is incorrect, you shouldn't be releasing it in the init method, just when dealloc is called (that's if you want to keep it as an ivar, you don't need to unless you need a pointer to it elsewhere since addSubview: will retain the view for you).
I believe the reason it's not actually crashing is because it's still being retained by the superclass (from the call to addSubview:), so when it's released in dealloc that's actually balanced out. The view probably removes itself from the superview when it's deallocated immediately afterwards, so when [super dealloc] is called it's not being over-released. That's my hunch, at lease.
Release in init is incorrect.
You mentioned "common practice" and an un-named book. I suggest looking at the canonical examples from Apple: ViewTransitions is a good example for this case (and 2 views to boot ;)
http://developer.apple.com/iphone/library/samplecode/ViewTransitions/index.html
(I don't have enough reputation to add comment yet.)
#bentford: Correct me if I'm wrong, but I believe that in order to use the imgView property's synthesized setter, you must use "self.imgView":
self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
If you don't have self., it's just using the ivar, and it's not getting the additional retain.
The basic answer is, there should only be one [imgView release] in the example code (whether it's after addSubview or in dealloc). However, I would remove [imgView release] from dealloc and leave it after addSubview.
There is a catch on the iPhone; with didReceiveMemoryWarning, you could have objects (including an entire view) released out from under you. If you have an application-wide retain set and you don't respect memory then you could find the application simply being killed.
A good example is:
if you think of a nested set of 3 views, View 1-> View 2-> View 3.
Next, consider the 'viewDidLoad' and 'viewDidUnload' calls. If the user is currently in 'View 3', it's possible that View1 is unloaded, and this is where it gets nasty.
If you allocated an object inside viewDidLoad and didn't release it after adding it to the subview, then your object isn't released when view1 is unloaded, but, view1 is still unloaded.
viewDidLoad will run again and your code will run again, but now you've got two instantiations of your object instead of one; one object will be in nowhereland with the previously-unloaded view and the new object will be for the currently visible view. Rinse, lather, and repeat and you find your application crashing from memory leaks.
In this example, if the given block of code is volatile and has a chance to be executed again (whether because of memory or an unloaded view), I would remove [imgView release]; from dealloc and leave it after addSubView.
Here is a link on basic retain/release concepts:
http://www.otierney.net/objective-c.html#retain
Yes, that code has problems. It releases the imgView too early which could potentially cause crashes in rare circumstances stores an object in an instance variable without retaining it, and it's just generally going about memory management the wrong way.
One correct way to do this would be:
#interface SomeViewController : UIViewController
{
UIImageView *imgView;
}
#property (nonatomic, retain) UIImageView *imgView;
And in the implementation;
#synthesize imgView;
Somewhere in the module:
//Create a new image view object and store it in a local variable (retain count 1)
UIImageView *newImgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
newImgView.image = [UIImage imageNamed:#"someimage.png"];
//Use our property to store our new image view as an instance variable,
//if an old value of imgView exists, it will be released by generated method,
//and our newImgView gets retained (retain count 2)
self.imgView = newImgView;
//Release local variable, since the new UIImageView is safely stored in the
//imgView instance variable. (retain count 1)
[newImgView release];
//Add the new imgView to main view, it's retain count will be incremented,
//and the UIImageView will remain in memory until it is released by both the
//main view and this controller. (retain count 2)
[self.view addSubview:self.imgView];
And the dealloc remains the same:
- (void) dealloc
{
[imgView release];
[super dealloc];
}