Which one of these is better practice?
A) retain and release the object myself later
NSMutableArray* array = [[self getArray] retain];
....
[array release];
B) autorelease from the function returning the object
getArray {
NSMutableArray* returnedArray = [[[NSMutableArray alloc] init] autorelease];
.....
return returnedArray;
}
The simplest rule of thumb when it comes to memory management in Objective-C is that you should release anything that you've explicitly allocated (alloc), copied (copy), newed up (new), or retained (retain).
The release should be done within the scope of the aforementioned actions. If you allocate space for an object that is returned by a method, you should autorelease it before returning it. So, given the two options you've provided, B is the recommended practice.
You could read and follow Apples guidelines on memory management and performance.
Personally I think the reasons for choosing one way over the other:
Using Autorelease pros:
You can't stuff it up, memory will be freed at some point. That I like to think of as "falling into the pit of success".
cons:
Using autorelease a lot may cause you memory problems as lots of objects build up awaiting be released by the autorelease pools.
Using retain/release pros:
More control when your memory is used/freed.
On ios apple recommends that you use release instead of autorelease whenever possible to keep the size of the pool small.
cons:
Like C/C++ malloc/free new/delete you have to be careful to keep them matched up and it is easy to stuff that up, causing memory leaks.
For member variables you have no choice, retain/release is it.
I think, whichever style you choose comes down to the situation your code is in and choosing the best style based on there pro's and con's. I don't think there is any one answer to this.
If you want to return an object you have to use the second approach. In all cases where possible you should use the retain-release approach because this uses less memory.
If you new, alloc init, retain, or copy (NARC) 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.
If you can choose, don't abuse autorelease when memory is a concern.
Some comments:
The first rule logically results in the second. Example: if the outcome of a function (the returned object) survives the execution of the function, all the function can do is autorelease the object.
Unless there is a memory/performance concern, the overhead of automatic memory management is better than the memory leak chances plus the increased developing time.
Try to retain/release symmetrically. Example: if you retained on init, then release on dealloc. Same for viewDidLoad/viewDidUnload.
If you use #property(retain) you have to release in dealloc.
Example:
// created with autoreleased, just call retain if you intend to keep it
NSString *orange = [NSString stringWithString:#"orange"];
// created for the caller, you'll have to release it when you are done
NSObject *apple = [NSString initWithString:#"apple"];
Related
Sometimes I see developers use:
ClassA *obj = [[ClassA alloc]...]autorelease];
Why does this sometimes autorelease the objects and sometimes not?
Or is this an error?
Autorelease just means "this will be released at a later date". If you autorelease something three times, it will be released three times, later.
Instead of guessing, read through and understand the Memory Management Programming Guide before you do anything else. It will save you a ton of time and frustration.
You also asked, in the comments to another answer, why people use autorelease to begin with. Autorelease is necessary for a common case where you have to create a new object and return it. By the other rules of memory management, you would need to release the object at some point or it would be leaked, but if you release it before you return it, it will go away immediately.
There are two ways that you could deal with this: a) to have these methods return a new object which the caller is expected to release when it is done with the object, and b) to make sure that the object is released as soon as the caller is done with it.
The way Cocoa and Cocoa Touch handle this situation by convention is option b): to use autorelease pools, because you won't have to keep track of ownership except for the objects you explicitly create. Some people use autorelease for nearly everything instead of release, and this is a bit more inefficient than release, but more importantly it hides any useful distinctions you might make between release and autorelease when you're trying to read, navigate and understand the code.
As I said earlier, please read the Memory Management Programming Guide and all these questions will be answered. Better yet, if you just follow the simple rules listed in there, you won't have to think deep thoughts about every combination; there'll be a general rule to follow for your situation and the rule will work.
There's no error with autorelease - it just sets the object to be automatically released at a later time, which you don't necessarily have control over.
I try to always explicitly release my objects, unless I don't have a choice such as when returning a newly alloced/init-ed object from a method.
Actually when you create an object by using the following statement,
ClassA *obj = [[ClassA alloc]init ...];
Then you need to release that object, other wise it will be remain in that app and not useful by any other objects. Then the memory will be wasted.
So we have to release the object by [obj release];
in case some time we can't release at specific time. So we will put autorelease. If we do like that then the NSAutoReleasePool handle the release operation.
We can use any of the above.
Reagrds,
Satya.
No, it's not an error at all. Autorelease means that the object will be released at the end of the current Autorelease pool.
Look at your main.m class file (Every Cocoa/Cocoa Touch project gets it). You will see it has a method that looks a bit like this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
UIApplicationMain(.....);
[pool release];
UIApplicationMain starts your app's run loop. When you reach the end of it, (The application is closed) anything in the autorelease pool is dumped.
Now, if you impliement multithreading and you create your own Autorelease pools within the pool, you'll release the object when that pool is released.
The documentation on the method is here: http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/autorelease
Should I release strPhone? What about the coreFoundation object being cast to an NSString? What happens to it?
strPhone = [[NSString alloc] initWithUTF8String: [[(NSArray *)ABMultiValueCopyArrayOfAllValues(theProperty) objectAtIndex:identifier] UTF8String]];
Thanks for helping me understand.
You should release or autorelease both. For the NSString, any time you use alloc + init to create an object you are settings its reference count to 1. You are responsible for releasing it when done or autoreleasing it now to allow it to be released at the end of the run loop.
For the CFObject, ABMultiValueCopyArrayOfAllValues returns a CFArray which is “toll-free bridged” to NSArray (meaning it can be used interchangeably with NSArray). Anytime a copy is done - as is implied by the method's name, you are responsible for releasing the returned object. Again, you can release it immediately after you are done with it or autorelease it now to have it be released when the run loop completes.
Yes, both. See Apple's memory management guide for a complete but still pretty brief rundown of memory management in Cocoa.
Remember to NARC on your memory management.
New, Allocate, Retain, Copy. Those are the methods that create objects that YOU'RE responsible for releasing. Aside from those four methods, any new object you get is autoreleased and you don't have to explicitly handle its deallocation.
I know this question looks like a dupe: I checked and it's not
In talking about NARC, the author of this blog says, "Personally, I like to immediately autorelease anything I NARC-ed, on the same line." This goes completely counter to all the examples I've seen on the Apple site and in books, where autorelease is only used when the object must be returned and cannot be released immediately. In general, the idea is that autorelease is memory intensive and can gum up your program (though it makes code cleaner). From Appress Beginning iPhone 3 Development:
these objects can have a detrimental
effect on your application’s memory
footprint. It is OK to use
autorelease, but try to use it only
when you really need to, not just to
save typing a line or two of code.
I am not asking if autorelease is worse than explicitly calling release (it is), but rather:
In most 'normal' situations on iPhone, just how bad is it to replace a later release with an earlier autorelease (in the same method)? Also, in what situations would it be absolutely prohibitive to do this?
My guess is that, compared to using a garbage collector (as MonoTouch apps do sucessfully), autorelease will hardly make a dent in your memory footprint, and that Vincent's advice it right on, and can make for cleaner code and less accidental memory-leaks.
There's nothing wrong with using autorelease, but when you allocate objects in a loop, you should always call release explicitly.
Using autorelease:
for (int i=0;i<1000;i++) {
NSString *s = [[[NSString alloc] init] autorelease];
}
// at this point, there are 1,000 unreleased string objects in memory
Using release:
for (int i=0;i<1000;i++) {
NSString *s = [[NSString alloc] init];
[s release];
}
// at this point, no string objects are "alive"
As you can see, you have to be really careful when using autorelease in loops.
You should be aware how autorelease works. Each thread in your application normally has a single autorelease pool. Objects can be registered in the pool. At the time they are registered, the pool determines the stackframe they belong to and will automatically pop the from the pool whenever that stackframe is left.
While this may seem costly (and it certainly is compared to direct retain/release), I don't think it even close to the cost a generation mark and sweep garbage collector can have.
Where autorelease really shines is in all situations where exceptions may be raised and there's no try/catch around. Autorelease is definitely preferable to a direct release in such cases.
There are, however, situations where you should avoid autorelease (the same goes for garabge collected environments where you should try to avoid these situations too). Creating temporary, autoreleased objects in a loop which runs a huge number of times is such a scenario, which puts significant stress on a garbage collector or the autorelease pool.
Replacing release with autorelease should be avoided in worker threads that are very simple and can live without the overhead of an autorelease pool. So the guideline is: Whenever you can avoid it, you should, whenever you're unsure autorelease.
I am a bit confused in the following two ways of initialisations.....
Way 1:
- (void) myMethod{
NSArray *myArray = [[NSArray alloc] initWithObjects:obj1,obj1,nil];
[self setClassArray:myArray];
[myArray release];
}
Way 2:
- (void) myMethod{
NSArray *myArray = [NSArray arrayWithObjects:obj1,obj2,nil];
[self setClassArray:myArray];
}
In way 1, I have used a alloc init method which is a instance method and as I have used an alloc statement I have to release the array myself.
In way 2, I have used a static method to initialze the array and as there is no alloc statement used I dont need to release the memory the system will take care of that.
Way 1, is time consuming and can to lead to memory leaks if not taken care
Way 2, is faster in writing and you dont need to take care of memory leaks
But , still i have seen the way1 used in standard source codes more often than the way2. I have no idea why people do this or if I am wrong at some place.
Answers and comments are oppenly invited. Please suggest the best programming practice.
Your second example uses a convenience constructor, which returns an autoreleased object. The question, then, is whether it's better to use autorelease or alloc/release. mmalc's answer on this StackOverflow thread explains the drawbacks of autoreleasing objects. (Basically, use alloc/release whenever possible.)
Also (this may be stating the obvious), some classes might not have convenience constructors, so when working with these you'd have to use alloc/release.
as i know,
[NSArray arrayWithObjects:obj1,obj2,nil];
returns an autoreleased object, smth like
[[[NSArray alloc] initWithObjects:obj1,obj1,nil] autorelease];
and I prefer not to manage memory with autorelease pool. maybe it's just a prejudice))
When using method 2 (autorelease) the object is released when the operating system feels it has no references.
But when using the manual release, as you typed in your code, you can release directly, or whenever you need to.
I usually prefer the second way, and if I recall correctly, this is also what the Apple docs reccommend (use autorelease where possible).
In Way 1 the memory gets released faster, so if you have a method that gets called in a loop or recursively, using autorelease may accumulate much memory, whereas alloc/retain will keep your memory footprint low.
On the other hand I assume that using autorelease is more efficient, because the autorelease pool can release a big chunk of memory at once, instead of small chunks again and again. Tough I may be wrong here.
I have a method that returns a NSMutableArray:
//implementation of class Students
-(NSMutableArray *)listOfStudents {
NSMutableArray *students = [[NSMutableArray alloc] init];
//add objects to students and other operations here
return students;
}
The problem here is, when and where do I release the object students? If it was an instance variable, I would add a [students release] in the dealloc method, but it's not. The class Students allocated the object, so it owns the new NSMutableArray and it must release it, right?
Since I can't release it before return it, the only option I see here is... return it as:
return [students autorelease];
But it doesn't feel right to use autorelease objects on the iPhone. This method will be called many times... and I would like to release the memory as soon as possible. Also, the autorelease pool is in the main function and it looks like it will take a while to clean the mess.
How would you do it?
I tend to avoid using autorelease wherever I can within my iPhone applications, but there are some cases where it doesn't hurt you that much. If the array that you're generating via this method will be retained for a reasonably long duration, then you won't be sacrificing any performance or memory usage by returning it as an autoreleased result.
However, if you will be using and discarding the returned object quite frequently, you may wish to do something different. I have a naming convention with my methods that if something is prefixed by "generate", like generateStudentsArray, it returns an object that is owned by the caller and must be manually released (like with copy). This helps to avoid using autoreleased objects, but it adds another thing to remember when doing memory management.
Additionally, because memory allocation / deallocation is costly (especially on the iPhone), you may wish to avoid the frequent allocations and deallocations within a method called quite a lot and instead recycle the mutable array by creating it ahead of time and passing it into the method, which only adds to the array's contents.
You're right, autorelease is the standard idiom to use in a situation like this.
UIKit actually creates an autorelease pool at the start of each event cycle and releases it at the end, so your autoreleased objects will get cleared up then; they won't be hanging around forever.
If you had a loop that was calling this method many times within a single event cycle, you might want to create your own autorelease pool inside that loop so that these objects get released at the end of each iteration, rather than building up loads of objects to be released at the end of the current event cycle.
But unless you're doing something like that, or you are encountering another specific out-of-memory situation, UIKit's standard autorelease pools should handle it fine.