What's the recommended approach for allocating an object in an instance methode, which will later on be returned? - iphone

For example look at the following example:
Code1
-(NSString*)getString{
return [[[NSString alloc] initWithFormat:#"test"] autorelease];
}
-(void)printTestString{
NSString *testStr = self.getString;
[testStr retain]
NSLog(#"%#",testStr);
[testStr release]
}
Code2
-(NSString*)getString{
return [[NSString alloc] initWithFormat:#"test"];
}
-(void)printTestString{
NSString *testStr = self.getString;
NSLog(#"%#",testStr);
[testStr release];
}
Code 1 and Code 2 should be valid Code Snippets and no leaks should appear.
Code 1 uses autorelease so the return variable has to be retained in printTestString and after using it released. So there is a small Overhead here because of autorelease.
Code 2 doesn't release the NSString in getString so you have to only release it after using it. Seems your have to write less and you dont have overhead because no autorelease is used.
Which one is the de facto "standard" approach that is used out there?
Another thing I was asking myself. Could the autorelease in getString and the retain with
[testStr retain]
be a problem, when the autorelease pool releases the variable right after
NSString *testStr = self.getString;
then the string would be gone. Is that possible or does the compiler prevent that sort of thing?
Thanks
-Sebo

Do this:
-(NSString*)getString{
return [[[NSString alloc] initWithFormat:#"test"] autorelease];
}
-(void)printTestString{
NSString *testStr = self.getString;
NSLog(#"%#",testStr);
}
Your getString method autoreleases the NSString, which means printTestString doesn't need to retain or release it. Autoreleasing in getString makes sense, because it alloced the object and is therefore the 'owner' of the object. I suggest studying Objective-C's memory management rules before proceeding, as they are very important.
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH

Jake's answer is correct for almost all of the situations you'll need to return an object from a method, but there are cases where you might want to return something that isn't autoreleased. From the Memory Management Programming Guide (Mac version, but they're the same rules):
You take ownership of an object if you
create it using a method whose name
begins with “alloc” or “new” or
contains “copy” (for example, alloc,
newObject, or mutableCopy), or if you
send it a retain message.
Also, from the Coding Guidelines for Cocoa:
In your methods and functions that
return object values, make sure that
you return these values autoreleased
unless they are object-creation or
object-copy methods (new, alloc, copy
and their variants). “Autoreleased” in
this context does not necessarily mean
the object has to be explicitly
autoreleased—that is, sending
autorelease to the object just before
returning it. In a general sense, it
simply means the return value is not
freed by the caller.
For performance reasons, it’s
advisable to avoid autoreleasing
objects in method implementations
whenever you can, especially with code
that might be executed frequently
within a short period; an example of
such code would be a loop with unknown
and potentially high loop count.
Therefore, methods containing the prefix alloc or new, or those that contain the word copy by convention will have you returning objects that are not autoreleased. In fact, the Clang Static Analyzer understands this convention and will assume non-autoreleased objects being returned from methods that follow these naming rules.
I've used the new prefix in situations where I preferred not to return autoreleased objects (tight loops where I didn't want to manage an autorelease pool, etc.). Again, returning autoreleased objects is what's recommended in almost all cases, but there are some times where you might want to avoid that.

Related

iPhone: using retain vs autorelease

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"];

iOS correct way (memory management) for a method to return a value

If I have a class named Foo and I have this function + getIds that should return ids. Would the correct signature of + getIds look like this:
+ (NSArray *)getIds {
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
return ids;
}
What I'm wondering is that if I should use autorelease on *ids? There is no other way I assume? I can't do [ids release] after the return statement right?
You can send autorelease message along with alloc, init messages. You can also do, return [ids autorelease]; Note: You should not do both at the same time ;-)
You can not return [id release], because release method itself returns nothing.
The typically-correct memory management for returned objects is to have the called method set it as an autoreleased object, except when the method name contains "copy", "new" or "alloc". In those cases (copy/new/alloc), the returned object is retained, and the caller owns it (i.e. the caller is responsible for making sure they are released).
The code you wrote in the question will do the correct thing - it will return an autoreleased object.
When the caller gets the NSArray back, they can use the object as much as they like, and if they don't need the object in future calls, then they don't need to do any extra memory management. At the end of the run loop, the NSArray will be released, which is the desired behavior. If the caller does need the object to live longer, then they have to call retain on it (or something equivalent to that, such as calling something else that calls retain on it), and then they take the responsibility to call release on it later.
Useful stuff:
Apple's iOS memory management guide
My personal memory management guidelines (shorter, more biased)
Understanding run loops
Also, this will all go away when ARC (automatic reference counting, in iOS 5) becomes the norm.
You are already autoreleasing the array, so calling autorelease a second time would be an error that might result in a crash. The fact that you can't do a release after the return (you've left the function by then) is one of the reasons autorelease exists.
About whether the method should return an autoreleased as opposed to a retained object: Only methods that start with alloc or new or contain copy (as in mutableCopy) shall return retained objects. All other method shall return autoreleased objects.

Correct use of autorelease

I am trying to understand why my application crashes and I am going through my code. I am pretty sure that this is a valid use of autorelease:
(part of the code)
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
return [NSArray arrayWithArray:ids];
}
Is this valid? The NSArray arrayWithArray returns an autorelease object doesn't it? I also have some difficulties in understanding the scope of autoreleased objects. Would the autoreleased object (if it is in this case) be retained by the pool through out the method that invoked the method that this code is a part of?
- (void)codeThatInvokesTheCodeAbove {
NSArray *array = [self.dao allQuestionsFromCategories];
...
}
Would the array returned be valid in the whole codeThatInvokesTheCodeAbove method without retaining it? And if it was, would it be valid even longer?
Got some issues understanding the scope of it, and when I should retain an autorelease object.
That is valid, but -- really -- you can just skip the [NSArray arrayWithArray:ids]; entirely as there is no need to create a new array.
An autoreleased object is valid until the autorelease pool is drained, which typically happens once per pass through a run loop (or "periodically, but never while your block is executing" when enqueuing stuff via GCD).
The documentation explains it all better than I.
There is no need to create an immutable array because the return will effectively "up cast" the NSMutableArray to NSArray. While this is meaningless at run time, it means that the caller cannot compile a call to a mutating method of the returned value without using a cast to avoid the warning. Casting to avoid warnings in this context is the epitome of evil and no competent developer would do that.
If it were an instance variable being returned then, yes, creating an immutable copy is critical to avoid subsequent mutations "escaping" unexpectedly.
Have you read the memory management documentation? Specifically, the part about autorelease pools? It makes it quite clear how autorelease works. I hate to paraphrase a definitive work.
[NSArray arrayWithArray:] returns an autoreleased object. If you want codeThatInvokesTheCodeAbove to take ownership of the array, you should call retain on it (and rename codeThatInvokesTheCodeAbove according to apple's guidelines). Otherwise, if you don't care that ownership of the object is ambiguous then your code is okay.
In other words, [NSArray arrayWithArray:] returns an array that you don't own, but you have access to it for at least this run cycle. Therefore, codeThatInvokesTheCodeAbove will have access to it for at least this run cycle. Ownership is not clear, since nobody called alloc, copy, new, or mutableCopy or retain. It is implied that NSArray called autorelease before returning the new array, thus relinquishing ownership.
My information comes from http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH.
So, to answer your question, yes your posted code is valid. Whether it's correct depends on what it is you are trying to accomplish.
Autoreleased object are objects that are marked as to be release later.
There is a very particular object that is automatically created by UIApplicationMain: an UIRunLoop.
Imagine it like a while structure, it cycle until application is terminate, it receives every event and properly resend it to your interested classes, for example. Just before UIApplicationMain there is a command to create an NSAutoreleasePool that, once the NSRunLoop is ready, attach to it. When you send an -autorelease command to an object, the NSAutoreleasePool will remember to release it when is released itself. It's dangerous to use it many times in platforms that has less memory (iOS devices), because objects aren't released when you send an -autorelease command but when the NSAutoreleasePool is drained (when app releases it).
If you want to free the non-mutable list before you return, you can use something like this:
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSArray* result;
NSMutableArray *ids = [[NSMutableArray alloc] init]; // AUTORELEASE REMOVED FROM HERE
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
result = [NSArray arrayWithArray:ids]; // COPY LIST BEFORE IT IS FREED.
[ids release]; // MUTABLE LIST FREES _NOW_
return result; // NONMUTABLE COPY IS RETURNED
}
It is not worth doing this unless your mutable array is likely to sometimes use a lot of memory.

Autoreleasing object returned from NSMutableArray

When a method returns an object that is taken from and NSMutableArray does the object must be autoreleased? Check the following method. Also should I autorelease the nil value?
-(NSObject*)getElementByID:(NSString*)ID{
for(int i=0;i<[elements count];i++){
NSObject *element = (NSObject*) [elements objectAtIndex:i];
if([element.key isEqualToString:ID]){
return [element autorelease];
}
}
return nil;
}
You must not autorelease element because you are not an owner of it (you have not put a retain on it). You would have become an owner of it if you acquired it using alloc, new or retain. Since you acquired this object calling objectAtIndex:, you do not own it. See Three Magic Words. Calling autorelease here will cause a crash later do to over-release.
Your method name is incorrect and breaks KVC. A method that begins with get must take a pointer that will be updated with the result. This should be elementForID:. As noted above with the three magic words, naming in ObjC is very important to writing stable code
As a side note, it is traditional to use id is most cases rather than NSObject*. They mean slightly different things, but typically id is correct.
You never need to do any memory management related things to nil. So, no, you should not send autorelease to nil.
You also should not need to send autorelease to the element object that you are returning from your elements array. That object you are returning will remain in memory by virtue of elements itself having retained it. If the calling method would like to retain the value that you return, it may. But if that calling method only uses the returned value within its own scope, it is safe for it to do so without retaining it.

releasing variables to save memory

I have a beginner's question about releasing variables and not wasting memory...
I don't quite understand when to release variables. I understand that I should always do this if I have assigned them in my header file (in my #interface section and my #property commands). I release them in my -(void)dealloc function.
However, what am I supposed to do with variables that I happen to use in some of my methods, e.g.:
for (int temp = 0; temp < 3; temp++) {
// do something...
}
[temp release];
This is obviously wrong (at least xCode tells me so), as 'temp' is undeclared. But why? I've declared it as an int and temp thus takes up space in my memory, I'm sure. How do I tell the program to free up the space temp has taken after I don't need it anymore? I'm sure this is obvious, but I simply don't get it.
I'd be very happy for any suggestions for a beginner of how not to be a memory pig and to have 'memory leaking' everywhere in my apps...
You declared it as an int in the scope of the loop. Once the loop is done, it goes out of scope.
Also, you can not release an int, which is a primitive type. You can only release a subclass of NSObject. A good rule of thumb is that you eventually have to release anything that you called alloc or retain on.
Edit: For your edification, memory management only applies to objects allocated from the heap. That would be NSObjects obtained via "alloc" or must C-level memory allocated with something like "malloc()". Declaring a variable like "int x" is called an "auto" variable in that is is created on the stack and will AUTOmatically disappear then that block ends (the end of a "block" being the end of the function or perhaps the end of a {} pair or even the end of a for/if/while block.
Since Objective-C is basically just a special version of C (with messages), it does not create permanent objects unless you explicitly tell it to. This is different form languages like Python or Javascript.
You only need to release objects, and temp is an int, not an object.
As far as when to release objects, Apple's docs explain that better than I can: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
You do only release objects, and not primitive types. For example you create an array with
NSArray *myArray = [[NSArray alloc] init];
This initialization allocated memory which you have to free after your done using your array, it's your responsibility, else there will be memory leaks. You can do that in the dealloc section of a controller, or at the end of a method, or even after you've enumerated through the array and no longer need it.
If you create instances of objects with other methods than alloc, copy or new(rarely used) you have to release them. If you call retain yourself on an object you have to release it as well.
Please refer to apples memory management rules, which have been posted earlier.
There are two ways to store information in RAM in C and c like things, primitives which are allocated automatically by the compiler, and memory chunks allocated by you in your program.
Variables allocated for you by the compiler are called "automatics" and can be marked by the essentially unused (because it is the default) "auto" keyword. Automatics are bound to the scope in which they are declared and go away when it ends. Regular variables, like "int x" are automatic.
Notably, pointers are typically automatic. However, the things they point to are not. Those would be the thing you asked to be allocated.
In objective-c, things are allocated with the alloc message. However, sometimes a class will call this for you, so you might not see it. To help make it clear what you should do, there is a tradition: If you get an object where you alloc'ed it, got it from a class method with the word "copy" in the method name, or sent it a "retain" message, then you own a share of it, and it won't go away until you send it a release message.
If you didn't get the object through one of those means, you must not release it, because you don't have a share in it.
So, in summary: regular variables (int, short, char, double, float, long) are automatic, no need to allocate it. Pointers are also automatic, however, the things they are pointing to are not. In obj-c, you own a share if you alloc'ed it, copy'ed it, or sent it a retain message.
You can't release an integer...
Release works only with instance of Objective-C classes.
Variables such as integers are placed on the stack, and they does not persist after a function/method call, unless allocated explicitely.
You only release objects. If you use the alloc, init procedure to create an object you must release it. If you retain an object you must release it. If you use a method that has the word "create" in it, you must release it. Anything else, the system will handle for you.
Primitives do not need to be released, only objects.
Biggest thing to keep in mind is that whenever you "alloc" or "retain" an object, put a corresponding "release" or "autorelease".
you see an error on the line [temp release]; because temp is not in scope. temp will not be seen outside of the for loop you created.
you do not need to clean up the memory of temp, since you have not claimed ownership of it(see Memory Management Rules): http://developer.apple.com/library/ios/#documentation/general/conceptual/DevPedia-CocoaCore/MemoryManagement.html
examples of objects where you do not need to release/manage memory:
NSArray *myArray = [NSArray array];
NSNumber *myNumber = [NSNumber numberWithInt:5];
NSString *myString = #"Hello World";
NSInteger i = 5;
int x = 2;
examples of objects where you do need to release/manage memory:
NSArray *myArray = [[NSArray alloc] initWithObjects:#"Hello", #"World", nil];
NSNumber *myNumber = [[NSNumber alloc] initWithInt:5];
NSString *myString = [[NSString alloc] initWithString:#"Hello World"];
-
typically, when your completely done using an object you own, you clean up its memory
see apple's docs for explanations on properties: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW1
setting a property with assign or readonly: you should not worry about releasing its memory, as you don't own it
property with retain or copy: you claim ownership of the object and need to release it at some point
this answer won't answer/solve all memory management questions/concerns, but it may shove you in the right direction