Is it better to autorelease or release right after? - iphone

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.

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.

Best practices, fire-and-forget asynchronous classes?

I have a class whose sole purpose is to go download a specific file off the net, store it locally and then return the local path of the stored file.
I use this class based on whether I have a local copy of the file in question or not, and I sometimes call it up multiple times at the same time, if more than one file needs downloading. The way I use it is simply
Loader *l = [[Loader alloc] initWithDelegate:self];
[l downloadFile:someFile];
[l release];
The thing is, in order to keep it around until it's done downloading, I am actually doing [self retain]; in the class, then [self autorelease]; when it's done. This feels hacky though. How do people deal with this?
I agree that [self release] and [self autorelease] feel weird, but that doesn't mean they're wrong. In some situations, they can be the right thing to use (and I've used them before).
If you want to avoid them, however, you might consider making a LoaderManager class that simply owns the Loader objects until they're done loading stuff. It'd essentially be a wrapper around an array, and you'd use it like this (or something):
#interface LoaderManager : NSObject {
NSMutableSet *loaders;
}
#end
#implementation LoaderManager
- (id)init {
self = [super init];
if (self) {
loaders = [[NSMutableSet alloc] init];
}
return self;
}
- (void)dealloc {
[loaders release];
[super dealloc];
}
- (void)addLoader:(Loader *)loader {
[loaders addObject:loader];
}
#end
And then your Loader object would do:
[myLoader downloadFile:someFile manager:aLoaderManager];
Which internally would simply invoke:
[aLoaderManager addLoader:self];
Under the circumstances, I think it's fine for your Loader to retain and autorelease itself. The most expedient solution might be to just add a detailed comment to your code that explains why it does what it does. The biggest problem is that Loader takes a delegate. Delegators don't usually retain their delegates in order to avoid retain cycles, but in this case it seems possible that the delegate could be deallocated before the Loader is finished downloading its file. If that happens, a crash is likely. So, if you want to continue with this fire-and-forget style, you might want to have Loader retain its delegate.

objective C (iphone) question about releasing

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).

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

Objective C iPhone when to set object references to nil

I have been developing with objective C and the Cocoa framework for quite some time now. However it is still not absolutely clear to me, when am I supposed to set object references to nil. I know it is recommended to do so right before releasing an object that has a delegate and you should also do so in the viewDidUnload method for retained subviews. But exactly when should this be done and why?. What does it accomplish exactly?. Thank you in advance.
-Oscar
Say you have a pointer myView defined in your class' interface:
#interface MyClass {
UIView *myView;
}
#end
Then in your code, at some point, you may release that variable:
[myView release];
After you do that, myView, the pointer, won't be pointing to nil, but will be pointing to a memory address of an object that may not exist anymore (since you just released it). So, if you happen to do something after this, like:
[myView addSubview:otherView];
you'll get an error.
If, on the other hand, you do this:
[myView release];
myView = nil;
...
[myView addSubview:otherView];
the call to addSubview will not have any negative impact, since messages to nil are ignored.
As a corollary, you may see suggestions of using retain properties, such as:
#property(retain) UIView *myView;
and then in the code, just do:
self.myView = nil;
By doing that, the synthesized accessor will release the old object and set the reference to nil in one line of code. This may prove useful if you want to make sure all your properties are both released and set to nil.
One thing that you must never forget, is that memory management is done by means of retain release calls, and not by means of assigning nil. If you have an object with a retain count of 1, and assign nil to it's sole variable, you'll be leaking memory:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0,10,10)];
view = nil;
// You just leaked a UIView instance!!!