objective C (iphone) question about releasing - iphone

If I create a view, and add it as a subview and also add it to an array, do I have to release it twice?
UIView* cat = [[UIView alloc] initWithFrame:someFrame];
[self.view addSubview:cat];
[self.animals addObject:cat];
[cat release];
[cat release];
It just seems weird to me to have 2 release statements, and I haven't seen people doing that. But doesn't the retain count increase by 2 in this case?

You should only have one release — to balance the alloc. Neither addSubView: nor addObject: give the caller ownership over the object, so the caller does not need to balance them with a release. Reading the memory management guide should clear all this up for you.
It might help to remember "NARC" — if you call a method on an object that includes the word "new", "alloc", "retain" or "copy", you need to release it. As you can see in your code above, only alloc fits the bill. Since you only NARCed it once, you only need to release it once.

In addition to what Chuck wrote:
It's not that you release because addSubview: or addObject: might/might not increase the retain count.
That's completely wrong way to look at it. If self.view retains your object, it's self.view's responsibility to release it correctly, and that's nothing you should care about.
It's because you created the object by alloc you need to release it.

When the cat is added to self.view, then self.view owns the cat, and it is responsible to release the cat. It is the same as for self.animals. The self.animals owns the cat. When self.animals is released, it will release all objects it owned.
So, you should release cat only one. Because in your code block, you own only one cat, not two.

As has been mentioned you do not have to release it twice; once is all that is required. However you do not have to release it at all if you use autorelease:
UIView* cat = [[[UIView alloc] initWithFrame:someFrame] autorelease];
[self.view addSubview:cat];
[self.animals addObject:cat];
The cat object will be released toward the end of the RunLoop cycle. Using autorelease will make your code cleaner and more able to cope with change.
Also you do not need the self qualifiers on view and animals unless you want to distinguish them from locally scoped objects (it'd also be poor practice to have locally scoped variables named the same as your classes' members).

Related

Can someone explain memory management

OK, so I am halfway through developing an iPhone app and I keep stumbling when it comes to memory management.
I have tried a number of times to understand this with very limited success. I consider myself to be above average intelligence, but this stuff just eludes me, despite repeated searches and reading of Apple documentation
Lets say I have a picker that I am creating - so the code goes
UIPickerView *patientPicker = [[[UIPickerView alloc] init]retain];
//more code here
[self.view addSubView:patientPicker];
So then I do a couple of different things with my picker.
The picker only appears when a segmented control button is pressed. The segmented control dictates which array of data is used to populate the picker.
However, when I change segmented control, I find that it displays a new picker on top of the old picker, rather than changes the data in the current picker.
i.e. segmented control is patient age or weight. If age is selected a picker of ages appears, and the same if weight is selected the picker of weight appears. However if one of the pickers is already present, then clicking on the alternate segment doesn't change the data, it just adds another picker onto the view.
My problem comes when I try and hide the picker as the old picker is still underneath, and I can't hide the old one.
So when I click a button to remove the picker, the old picker is still present underneath.
I have tried
[patientPicker removeFromSuperView];
but when I try and rebuild my picker I am advised that patient Picker has been deallocated???
The same goes for
[patientPicker release];
I know that someone would be able to tell me the simple answer, but what I really want is a really simple/dumbed down explanation of memory management so that I don't have to ask again.
Pretend I am 7 years old!
Thanks
Bob
UIPickerView *patientPicker = [[[UIPickerView alloc] init] retain];
Here you don't/shouldn't do a retain. The init call already implies that the caller is responsible for the create object (in other words, init has a retain implied). You need a release for every init and retain.
I reckon that you doing an alloc/init each time the segmented control changes selection. What you can do is, In the vieDidLoad, do this:
UIPickerView *patientPicker = [[UIPickerView alloc] init;
//more code here
[self.view addSubView:patientPicker];
patientPicker.hidden = YES;
[patientPicker release];
When the selection is made on segment control, set the hidden property of the picker to NO and set the datasource according to the selection
this sounds like a job for a tool... yes! hit Build and Analyze and remove every issue =) but understand why the static analyzer flags your program, and understand that there's quite a bit it can catch, yet quite a bit that it can't prove is a reference count imbalance and will not flag these. then run with leaks instrument and fix all issues, etc. and if you run into deallocated instances, run zombies instrument and fix all issues.
anyways, there's more to it! here are some points to your code.
UIPickerView *patientPicker
= [[[UIPickerView alloc] init]retain]; // << do not retain here. alloc
// returns an object you must release
[self.view addSubView:patientPicker]; // << self.view will retain its subviews.
// ok, that makes sense that the view
// would want to hold onto a reference to
// ensure the view is not destroyed
// while it's still a subview.
[patientPicker removeFromSuperView]; << the superview will release its subview
[patientPicker release]; << your life will be easier if you use the accessors
when you're dealing with reference counting, you need to hold a reference to use an object. so, let's take autorelease pools out of the equation. using autorelease only when needed will help you learn, and make some of your issues local to the callsite -- avoid calling autorelease where possible while you are learning.
NSString * a = [[NSMutableString alloc] init]; // << I hold 1 reference
[a length]; // ok
[a retain]; // << I hold 2 references
[a release]; // << I hold 1 reference
[a release]; // << I hold 0 references
[a length]; // expect bad things
now let's illustrate autorelease pools:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * a = [[NSMutableString alloc] init]; // << I hold 1 reference
[a length]; // ok
[a retain]; // << I hold 2 references
[a release]; // << I hold 1 reference
[a autorelease]; // << add a to pool. when pool is destroyed a release message will be sent to a
[a length]; // ok. a is still alive. its release message is deferred until the pool is destroyed
[pool release]; // pool's reference count has reached zero. pool will call [a release]. pool will be destroyed.
[a length]; // expect bad things
Two rules of memory management:
If you new, alloc init, retain, or copy (N.A.R.C.) an object, you have to release it.
When the name of a method starts with any of those words, it means it's being created for the caller, who has the responsibility to release the object when he is done with it. Otherwise the method returned is not owned by the caller, and he has to indicate he wants to keep it calling retain on the object.
Note that the first rule results in the second. A method creates an object (therefore it is responsible for releasing it) but if the outcome of the method (the returned object) survives the execution of the method (so it can be handed to the caller) all the method can do is autorelease the object. An autorelease adds the object to the autorelease pool, which will release the object at some point in the future.
Example:
[[MyObject new]; // 1)
[NSString initWithFormat:#"%d",1]; // 2)
[NSString string]; // 3)
1) Name contains new, so it will need release.
2) Name contains init, so it will need release.
3) Name doesn't contain any of the NARC words so you know it returns an autoreleased object. This means you need to retain it if you intend to keep it, and if you do, you will need to release it later. Otherwise just use it and forget about it.
Couple of tips:
Try to retain/release symmetrically so you don't lose track of what to release and where. Example: if you retained on init, then release on dealloc. Same for viewDidLoad/viewDidUnload.
If you can choose, don't abuse autorelease when memory is a concern so you recover your memory as soon as possible. Abusing autorelease is also a sign you don't understand memory management.
Your example (same thing Justin told you):
UIPickerView *patientPicker = [[UIPickerView alloc] init]; // 1)
[self.view addSubView:patientPicker]; // 2)
[patientPicker release]; // 3)
1) We call alloc init so you know this object will need release once you are done with it.
2) addSubView calls retain internally. Why? When you receive an object and you intend to keep it, you express that intention calling retain, which also gives you the responsibility of releasing it. When a UIView is released, its implementation also releases its subviews to balance the retain done before by addSubView.
3) We won't be using it anymore so we call release. Now self.view is the owner of the object.
As an exercise, try to implement your own setter and getter for a variable and run Build and Analyze to see what Xcode thinks about it.
Focus on Ownership, if you have ownership; you have to release object. If you don't have ownership don't dare to release it.
id myObject;
myObject = [abc retain] => you are the owner
myObject = [[abc alloc] init] => you are the owner
myObject = [abc copy] => you are the owner
myObject = [[[abc alloc] init] autorelease] => you are not the owner
(everywhere you put autorelease you loose the ownership)
myObject = [abc xxxWithYYY] => you are not owner
(as a convention, a method returning object always give an autorelease object)
There will be some more similar conventions where you can identify OWNERSHIP; I just jotted down what I can recall now.

Ignore 'Object sent -autorelease too many times" warning

When running Analyzer, I receive the "Object sent -autorelease too many times" warning. I know I'm doing something tricky (and am open to alternatives to accomplishing my goal).
Essentially, I wanted to keep a stack of specific types of controllers handy for sending messages from a central location. So, considering:
From 'ActionBroker' shared object:
NSMutableSet *liveActions;
liveActions = [NSMutableSet alloc] init];
...
CLViewController *action = [[[actionClass alloc] init] autorelease];
if (!action) {
return nil;
}
[self.liveActions addObject: action];
// When adding an object, the retain count is increased. We want the action
// to dealloc, so that it might remove itself from the list...
[action release];
return action;
And the complementary dealloc code:
[[CLActionBroker sharedActionBroker] removeAction: self];
[super dealloc];
... and in removeAction:
[action retain];
[self.liveActions removeObject:action];
The above code works, I just get the nagging error. And the nagging sensation that I could probably solve the problem a different way.
One of the use cases for this code is to pass an 'handleOpenURL' request through a chain of open controllers and returning the first 'YES' response.
As I understand it, your intent is to have a set of controllers ("actions") in the set, which you could easily access from anywhere in your app. If one of these controllers is deallocated, it would automatically remove itself from the set.
There's a problem with this setup, though. As you've described it above, the controller is supposed to be removed from the liveActions set upon deallocation. But since an NSSet retains its members, your controller will never be deallocated so long as it is still in the liveActions set. -dealloc is only run when all retains have been balanced by a release.
This, then leads to your over-release, which leads to the warning. Since you've sent an extra release, -dealloc could be run while the controller is still in the liveActions set. But when you remove it from that set, it's going to send a release message to your object, which would take its retain count negative. That may or may not be safe, but in either case it's an ugly workaround.
What you really want, it seems, is a set that does not retain its members. This is normally a dangerous configuration, since it can lead to dangling pointers in the set. But if you're willing to manage the lifetime of the object and clear out those dangling pointers at the appropriate times, it turns out that it's quite doable. You just need to use a CFMutableSet instead of an NSMutableSet. And since the two are toll-free bridged, it doesn't even add that much complexity.
Setting up the CFMutableSet looks like this:
// The NULL for the third parameter tells the set to not do anything when
// an object is added to or removed from the set.
CFMutableSetRef cfLiveActions = CFSetCreateMutable(NULL, 0, NULL);
// Toll-free bridging makes this possible
NSMutableSet *liveActions = (NSMutableSet *)cfLiveActions;
After that, you can use it exactly as you would use any other NSMutableSet; this one will just be special in that it won't retain its members.
The problem:
CLViewController *action = [[[actionClass alloc] init] autorelease]; // +0 ownership
// ...
[self.liveActions addObject: action]; // liveActions takes ownership
// ...
[action release]; // -1 ownership
When you've alloced the object, you are responsible for it. But then when you autorelease it, you've fulfilled your obligation (and because you autoreleased instead of releasing, you can still use the object until the next turn of the runloop). You shouldn't release it again later.
Also:
[action retain];
[self.liveActions removeObject:action];
The retain is unnecessary.
(And here's another plug for beginning to switch to ARC, under which you won't have to worry about this!)
[Edit: misunderstood your question. Revised answer forthcoming.]
[Edit 2: never mind... even though I misread your intent, I believe my solution is still right.]

Where I should call [object release]?

I've subclassed some UITextField and added some custom properties.
In a UITableViewController, in the ViewDiDLoad I init them, and in the cellForRowAtIndexPath I add them to the cell with [cell.contentView addSubview:customTextField];
Each cell has a different customTextField as all of them are very different.
Where I should call the [customTextField release] ?
After I add them to the cell view ?
If for example I call [self.tableView reloadData] my customTextField are going to be added again to the cell, so maybe I should change my approach in doing this ?
thanks for the orientation ...
regards,
r.
You release an object when you no longer have any interest in it. This happens for many reasons; it might be because you've finished with the object, or have passed the control over the object lifetime to another object. It might be because you're about to replace the object with a fresh instance, it might be because you (the owner object) are about to die.
The last one seems to be relevant in your case. You create these object in viewDidLoad and repeatedly need them (i.e. to add them to cells) until your object is no longer functioning. In this case, just as you create them in viewDidLoad, you can release them in viewDidUnload.
Edit: I should really mention autorelease, but this isn't relevant in this instance. Memory management is best handled with a notion of 'owner' - the person who creates something (or retains it) should be responsible for deleting it (or releaseing in ObjC parlance). autorelease handle some cases where you need to give an object to an alternate owner, having previously owned it yourself (typically via a method return). If you are the creator, you can't just release it before returning it to the new owner, as it will be deleted before the new owner has a chance to stake an interest in it. However, you can't just not release it; it will leak. As such, the system provides a big list of objects that it will release on your behalf at some point in the future. You pass your release responsibility to this list, then return the object to the new owner. This list (the autorelease pool) ensures your release will occur at some point, but gives the new owner a chance to claim the object as theirs before it's released.
In your case, you have a clear interest in owning the objects for the lifetime of your view controller - you need to, at any time, be able to add them to view cells in response to a table data reload. You're only done with them when your view controller dies, so the viewDidUnload (or possibly dealloc) is the only sensible place to release them.
I always release my controls directly after I added them to a view using addSubView. When I work with tables, I also initialize them in the cellForRowAtIndexPath method.
Therefor the object stays alive the shortest time.
Adam Wright explains the theory of this very well, but let me give you some practice. You're thinking about this problem far too hard, and that almost always leads to bugs. There is a simple solution that solves this problem almost every time: Retain all ivars using accessors; don't retain non-ivars.
.h
#interface ... {
UITextField *_customTextField;
}
.m
#property (nonatomic, readwrite, retain) UITextField *customTextField;
...
#synthesize customTextField=_customTextField;
-(void)viewDiDLoad {
self.customTextField = [[[UITextField alloc] init....] autorelease];
}
...
- (void)dealloc {
// I do not recommend accessors in dealloc; but everywhere else I do
[_customTextField release]; _customTextField = nil;
}
Never access your ivars directly, except in dealloc (even that is controversial and some people recommend self.customTextField = nil; in dealloc; there are arguments either way). But never assign your ivars directly. If you will follow this rule, you will find that most of your memory problems go away.
The safest way to handle object ownership is to autorelease the view directly after initialization:
FooTextField* textField = [[[FooTextField alloc] init] autorelease];
[myCell.contentView addSubview:textField];
Adding the text field to a superview (the UITableViewCell's contentView) retains it. This way you don't have to care about releasing the view afterwards.
There seems to be a resentment against autorelease in the iPhone developer community. In my opinion, this resentment is unfounded. Autoreleasing an object adds very little overhead to the program if the objects lives longer than the current pass through the run loop.
Every object in Obj-C has a reference counter (retainCount), and when this counter goes to 0 the object is deallocated. When you allocate and initialize an object, the reference count is set to 1 - but you can retain it as many times you want to.
UITextField *textField = [[UITextField alloc] init]; // Reference counter = 1
[textField retain]; // Reference counter = 2
[textField retain]; // Reference counter = 3
The opposite of retain is release, which subtracts from the reference counter;
...
[textField release]; // Reference counter = 2
[textField release]; // Reference counter = 1
You can always get the reference counter of your objects;
printf("Retain count: %i", [textField retainCount]);
The method addSubview of UIView does retain your passed in sub view - and when it's done with it it releases it. If you need your UITextField later, in another scope (when the UIView is done with it and has released it) - you should not release it after you've added it to the super view. Most of the time you actually don't need to hold on to a reference, so you should release it after you've added it to the super view. If you dont - you can release it in the dealloc method of your scope.
Take a look at UITableView -dequeueReusableCellWithIdentifier: and -initWithStyle:reuseIdentifier:.
In -tableView:cellForRowAtIndexPath:, use -dequeueReusableCellWithIdentifier: and check if the result is nil. If it is, instantiate a new cell with -initWithStyle:reuseIdentifier:.
Send -autorelease to your customTextField upon creation and adding to the respective cell.
You should not add subview in cellForRowAtIndexPath! This will slow down the view as you add a subview each time the cell is displayed. Try using custom UITableViewCell class for that purpose.
Here is a perfect solution of UITableView customization
http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html
works jut perfectly

Autorelease vs. Release

Given the two scenarios, which code is best practice and why?
Autorelease
loginButton = [[[UIBarButtonItem alloc] initWithTitle:#"Login"
style:UIBarButtonItemStylePlain
target:self
action:#selector(loginButtonClicked:)]
autorelease];
self.navigationItem.rightBarButtonItem = loginButton;
or
Release
loginButton = [[UIBarButtonItem alloc] initWithTitle:#"Login"
style:UIBarButtonItemStylePlain
target:self
action:#selector(loginButtonClicked:)];
self.navigationItem.rightBarButtonItem = loginButton;
[loginButton release];
For your example, it doesn't really matter. Personally, I would probably use the first case. That would let you add modifications or debugging code later without having to worry about moving the [loginButton release] line around.
There seems to be a stigma against using autorelease (i.e. prefer to release whenever possible), which is why I typically go the second route. But since you're not in a loop here, releasing now vs. autoreleasing later will have exactly the same effect (since another object has retained loginButton, it won't be dealloc()ed).
But I should point out that most of my memory leaks are caused by forgetting to add the release line, so it would probably be better to just tack on the autorelease right away.
Either will be just fine in your case, as Carl says. It is because the UIBarButtunItem object stays in the memory because one reference to it is kept inside self.navigationItem (assuming you declared that property with #property (retain).). Therefore, the usual diatribe against using the autorelease pool, that it keeps unnecessary objects in memory until the end of the current event loop, doesn't apply here.
Since you're on a very tight memory budget on the iPhone, the preferred way should be through explicit release. This way objects don't stick around until the autorelease pool gets emptied during the runloop and you are able to keep your memory footprint as small as possible.
Since the navigationItem retains it, the two end up being identical. Style-wise, autorelease is preferred for returns from methods that don't say alloc or copy in their name, but otherwise it is up to you. If the object wasn't separately retained, release would free up the memory faster.
The code-style issue of setting a reference to nil after release is a related question.
When you send an -autorelease message to an object, you're adding it to a list, and it will get a -release message when the autorelease pool is released. The entire purpose of -autorelease is to provide a way for you to balance your retains and releases when something else might still want the object you're releasing, but you don't. In the situation you describe, the second example you gave is better.
Though in the presented scenario the two cases are identical but there is a slight speed advantage to using release (reference )over autorelease.So when there are strict performance requirements go with release

Is it better to autorelease or release right after?

There are a lot of cases in which one would alloc an instance, and release it right after it's being assigned to something else, which retains it internally.
For example,
UIView *view = [[UIView alloc] initWithFrame...];
[self addSubView:view];
[view release];
I have heard people suggesting that we go with autorelease rather than release right after.
So the above becomes:
UIView *view = [[[UIView alloc] initWithFrame...] autorelease];
[self addSubView:view];
What's the best practice here? Pros and cons?
In most cases, it wont really matter either way. Since -autorelease simply means that the object will be released at the end of the current iteration of the run loop, the object will get released either way.
The biggest benefit of using -autorelease is that you don't have to worry about the lifetime of the object in the context of your method. So, if you decide later that you want to do something with an object several lines after it was last used, you don't need to worry about moving your call to -release.
The main instance when using -release will make a noticeable difference vs. using -autorelease is if you're creating a lot of temporary objects in your method. For example, consider the following method:
- (void)someMethod {
NSUInteger i = 0;
while (i < 100000) {
id tempObject = [[[SomeClass alloc] init] autorelease];
// Do something with tempObject
i++;
}
}
By the time this method ends, you've got 100,000 objects sitting in the autorelease pool waiting to be released. Depending on the class of tempObject, this may or may not be a major problem on the desktop, but it most certainly would be on the memory-constrained iPhone. Thus, you should really use -release over -autorelease if you're allocating many temporary objects. But, for many/most uses, you wont see any major differences between the two.
I agree with Matt Ball. Let me just add that, if you find yourself using this pattern frequently, it can be handy to write a quick category:
#interface UIView (MyCategories)
- (UIView *)addNewSubviewOfType:(Class)viewType inFrame:(NSRect)frame;
#end
#implementation UIView (MyCategories)
- (UIView *)addNewSubviewOfType:(Class)viewType inFrame:(NSRect)frame
{
UIView * newView = [[viewType alloc] initWithFrame:frame];
[self addSubView:newView];
return [newView autorelease];
}
#end
Which can be used as follows:
UIView * view = [someView addNewSubviewOfType:[UIView class]
inFrame:someFrame];
And it even works with other types, as long as they are derived from UIView:
UIButton * button = [mainView addNewSubviewOfType:[UIButton class]
inFrame:buttonFrame];
I usually go for -release rather than -autorelease whenever possible. This comes from years of experience debugging and enhancing other people's Objective-C code. Code that uses autorelease everywhere makes it harder to debug when an object gets over-released, since the extra release happens far away from the incorrect code.
It's also the case that many folks use autorelease when they just don't understand how cocoa memory management works. Learn the rules, learn the API, and you'll almost never need to autorelease an object.
A last minor point is that if you don't need the autorelease behavior, then using autorelease just needlessly adds extra work for your program to do.