Objective-C - Best practice for writing a simple method? - objective-c

In the following function which one is the best practice?
To send an autoreleased object, and make the caller retain it?
or send an allocated object, and make the caller release it?
- (NSString*) convertDataToString :(NSData*)myData
{
//just an example, method might not exist
NSString *str = [[NSString alloc] initWithData:myData];
return str;
return [str autoRelease];
}

Following up on #Chuck's comment, -convertDataToString must not return an object that the caller must release. That would violate the Three Magic Words. If you do not have "copy," "alloc," or "new" in your name, the caller cannot be expected to release the object. If you have "copy" in your name or start with "new" or "alloc," then the caller must release the object.
Objective-C relies heavily on consistent naming and the names mean things. If you learn the naming, then you won't have any problems.

The memory management rules say your first example is — and this is a direct quote — wrong. It's not even a matter of preference, as some answers here seem to indicate. The caller does not normally own the object you return, so it should be autoreleased.
The specific example from the rules says this:
This is wrong. Following the ownership policy, it would result in a memory leak.
– (NSArray *)sprockets {
NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,
auxiliarySprocket, nil];
return array;
}
The object’s reference to the new array object is limited to the sprockets method. After the method returns, the object loses its reference to the new object so cannot relinquish ownership. That in itself is not a problem. However, following the naming convention set out earlier, the caller is given no indication that it owns the returned object. The caller would therefore not relinquish ownership of the returned object, leading to a memory leak.

You'd want to return an autoreleased object most of the time.
Unless your method name contains one of the following words [alloc, new, copy], you should return an autoreleased object.

If you create, alloc, or copy an object, you are responsible for releasing it. Based on this, you should return an autoreleased object.

I prefer to return the autorelease. It means that you aren't hunting around trying to find where memory is being freed. Keeping memory allocation and deallocation together makes your life easier. After all, you're coding this, why make it harder on yourself.

Both are acceptable, but you should name your method accordingly : if the caller has the responsibility to deallocate it, you have to make this explicit by having your method name contain "create", "alloc" or "copy", else it should not.
More reading on this at http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH
It might be a bit more customary to return an autorelease object, but both are okay.

Related

Do we have to retain object returned by a method in non-ARC?

Consider a situation implemented in Manual Retain Release, where I have a variable pointing to an object returned by a method.
{
...
NSString *str = [self myNewString];
...
}
- (NSString *)myNewString
{
NSString *myString = [NSString stringWithFormat:#"%d-String", 1];
return myString;
}
Here do we have to retain the object returned by myNewString so that it wont be released while we are using it?
Please help I am new to Objective-C. Thanks in advance.
There are two aspects to this answer:
First, you want to conform to the method naming rule, that dictates that any method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” should have a +1 retain count (i.e. ownership is transferred), otherwise it should be an autorelease object (or, more accurately, any object whose ownership is not transferred, and if the caller wants to claim ownership, it would have to manually retain it).
By the way, ARC uses these method name prefixes to determine the object memory semantics automatically, but in manual retain and release (MRR) code, the burden rests with the programmer to ensure that the memory management of the method conforms to the semantics implied by the method's name. Following this method naming rule will become important if you ever integrate this MRR code with ARC code at some future date. There are code hints you can use if you have legacy code that violates this method naming convention, but it's really just better to make sure your code's memory semantics are in conformance with this method naming rule.
Regardless, this method naming rule is included in the Basic Memory Management Rules outlined in the Advanced Memory Management Programming Guide.
So, in manual retain and release, you have one of two choices. If the method starts with “alloc”, “new”, “copy”, or “mutableCopy”, then it should transfer ownership by returning a +1 retainCount object, e.g.:
- (NSString *)newSomeString
{
return [[NSString alloc] initWithFormat:#"%d-String", 1];
}
otherwise, it should not transfer ownership (e.g. return an autorelease object), such as:
- (NSString *)someString
{
return [NSString stringWithFormat:#"%d-String", 1];
}
So, if the caller wanted to make sure the object was retained, it could either just call the method that returned the +1 object:
NSString *string = [self newSomeString];
or, call the version that returns an autorelease object, but then explicitly retain it:
NSString *string = [[self someString] retain];
In practice, the latter convention, the someString example, is more common (use method that returns autorelease object, i.e. where the method name does not start with “alloc”, “new”, “copy”, or “mutableCopy”; and then if the caller needs to retain it, it should just explicitly do so). The new, copy, and mutableCopy methods all are generally used within respective, very specific contexts, which don't apply here.
By the way, if you run your code through the static analyzer ("Analyze" on Xcode's "Product" menu), it does a remarkably good job warning you if your MRR code has issues with over retaining objects or failing to retain them.
But bottom line, carefully follow the basic memory management rules, including the convention for naming methods, and then if you need it retained, explicitly retain your autorelease object or call a method that returns a +1 retainCount object.
Here you are passing just the address of location where NSString object is stored. So, definitely object would be retained by compiler. But you don't have to worry. ARC will take care of releasing memory once the reference count is 0.
Here you go Learn more about ARC
Basically any method that returns a new object besides new/alloc+init Returns it without ownership, meaning that you can count on it sticking around until the enclosing autoreleasepool drains, but no telling after that. If you want to keep it around longer, you must retain it.

When and when to not allocate memory to objects

NSArray *array = [dictionary objectForKey:#"field"];
and
NSArray *array = [[NSArray alloc] initWithArray:[dictionary objectForKey:#"field"]];
I see both kind of approaches very frequently in objective C code.
When tried to understand, I found both of them used in similar situation too, which makes contradiction. I am not clear on when I should use 1st approach and when 2nd one?
Any idea?
Detailed explanation and useful references are moms welcome.
First off, those two examples are doing slightly different things. One is retrieving something from an existing dictionary and one is creating a new array by retrieving something from an existing dictionary (the value of that key is an array).
But, if you're asking the difference between getting objects by alloc vs. convenience methods. ([NSString alloc] init vs [NSString stringWith ...), by convention, you own anything that you call alloc, new copy or mutableCopy on. Anything that you call that is not those, is autoreleased.
See the memory guide here. Specifically, look at the rules.
Getting an autoreleased object means it will go away at some point in the near future. If you don't need to hold onto outside the scope of that function, then you can call autorelease on it or use one of the convenience methods that's not alloc, etc...
For example:
// my object doesn't need that formatted string - create the autoreleased version of it.
- (NSString) description {
return [NSString stringWithFormat:#"%# : %d", _title, _id];
}
// my object stuffed it away in an iVar - I need the retained version of it. release in dealloc
- (void) prepare {
_myVal = [[NSString alloc] initWithFormat:"string I need for %d", _id];
}
In the first example, I created a convenience methods for others to call, my class doesn't need that object beyond the scope of that method so I create the autoreleased version of it and return it. If the caller needs it beyond the scope of his calling method, he can retain it. If not he can use it and let it go away. Very little code.
In the second example, I'm formatting a string and assigning it to an iVar variable that I need to hold onto for the lifetime of my class so I call alloc which will retain it. I own it and releasing it eventually. Now, I could have used the first version here and just called retain on it as well.
You have a fundamental misunderstanding of allocations versus instance methods.
The first example, NSDictionary's -objectForKey method, returns id, not an instance of NSDictionary, therefore it does not allocate or initialize the variable.
The second, however is the classic retain part of the retain-release cycle.
The two methods are fundamentally equal (if we are to assume that array is alloc'd but empty in the first, and nil in the second), and both get ownership of the array object. I would go with the second, as it guarantees a reference, and it's shorter.
What I think you're confusing this with are new and convenience methods. Convenience methods (like NSNumber's +numberWithInt:, NSString's +stringWithFormat:, and NSMutableArray's +array), return an autorelease instance of the class (usually). New takes the place of alloc and init in just one word.

Retain/release of returned objects

I am new to Objective-C, so this might be a dumb question.
I cannot help but see the similarities between ObjC and Microsoft's COM with respect to memory management (AddRef/Release vs retain/release). In a COM environment, it's more or less imposed on you to always AddRef (retain) an object before returning it to the caller. From what I've seen so far (I'm a third through Cocoa® Programming for Mac® OS X (3rd Edition)), the memory management part is somewhat fuzzy.
Assuming there is no GC, what is the idiomatic way to return an object?
Read Memory Management Programming Guide about autorelease pools.
In Objective-C, by convention, objects should be returned autoreleased (unless the method returning the object has a name that begins with “alloc”, “new”, “copy”, or “mutableCopy”). Autoreleased objects are tracked by Objective-C in a pool and automatically handled, which means you don't need to care about sending a final release to them. This greatly simplifies reference counting compared to COM, and this is why you're not seeing any release calls on returned objects most of the time. In contrast, the same convention specifies that all objects returned by a method whose name begins with alloc, new, copy, or mutableCopy, are the responsibility of the method caller. You have to manually call release on these objects or your program will have memory leaks.
Cocoa goes around the limitations of AddRef/Release in COM by introducing a third sibling; autorelease.
retain - I need this, make it stick around.
release - I don't need this anymore, you may remove it immediately.
autorelease - I don't need this, but let it stay around a few seconds in case someone else wants to pick it up first.
This tiny addition allow most return values to be handles as-if we had garbage collection. If you are not interested in keeping the return value around, just do nothing extra.
In order to get this to work there is a convention (a convention good enough to let the compiler do the memory stuff automatically for you with upcoming ARC):
Method names beginning with these must return retained instances:
alloc
copy
new
retain
All other must return autoreleased instances.
Three example implementation for how this can be applied in practice:
-(NSString*)newHelloWorldString {
NSString* s = [NSString stringWithString:#"Hello world"];
// Apply retain because s in now autoreleased
return [s retain];
}
-(NSString*)helloWorldString {
NSString* s = [[NSString alloc] initWithString:#"Hello world"];
// Apply autorelease because s is now retained.
return [s autorelease];
}
-(NSString*)fullName {
// No memory management needed, everything is autoreleased and good.
NSString* fn = [self firstName];
NSString* ln = [self lastName];
NSString* s = [NSString stringWithFormat:#"%# %#", fn, ln];
return s;
}
Generally something like
return [object autorelease];
and you can retain on the other end.
If you are planning to deploy on Lion/iOS5 or are using the latest SDK then also check out ARC.
Essentially i would recommend making the class that receives it retain it. i.e class stackoverflow receives object answer.
i.e
-(void) setAnswer:(Answer*) _answer{
self.answer = _answer; // If the answer is created from a returned message.
[_answer release];
}
edit: I think I might have put up the wrong stuff up there now that i am looking at it the 2nd time . Meant something along the lines:
Answer *_answer = [stackoverflow createAnswer];
self.answer = _answer;
[_answer release];
If you return an object , it is up to the owner to retain it , i would avoid autoreleases wherever possible because once the nspool kicks in, those objects are gone and if they are still used, it will cause problems.
i.e Answer *answer = [stackoverflow getAnswer] and if answer was created in the getanswer method then whomever is retrieving it is responsible in releasing it.
Makes sense?

Memory cleanup on returned array from static method (objective-c)

In objective-c, I have a utility class with a bunch of static methods that I call for various tasks. As an example, I have one method that returns an NSArray that I allocate in the static method. If I set the NSArray to autorelease, then some time later, the NSArray in my calling method (that is assigned to the returned pointer) losses it's reference because the original form the static method is cleaned up. I can't release the NSArray object in the static method because it needs to be around for the return and assignment.
What is the right way to return an object (like the NSArray) from a static class, and have it hang around for the calling class, but then get cleaned up later when it is no longer needed?
Do I have to create the object first in the caller and pass in a pointer to the object and then return that same object form the static method?
I know this is a basic O-O problem, I just never had this issue in Java and I do not do much C/C++.
Thanks for your help.
Your autorelease is correct in the return just retain it when you call the static method.
NSArray *data = [[StaticClass getArray] retain];
If you have a property for the place your assigning the return value to, you can just do self.data = .. and the retain is automatic.
Please take the time to read over the rules. These apply to all of the frameworks you'll be using, and should apply to your code as well. Burn these into your head, and they'll become second nature. Thankfully, it's not complex, rather simple.
It's quite simple. If you do not own an object, it will go away at some indeterminate point in the future. In your case, the "indeterminate" point is when the autorelease pool gets drained, which in the normal case, is at the end of processing the current event.
If you want an object to hang around, you need to own it. The memory management rules referred to by jer will tell you exactly how you get ownership of an object. In this case, you need to retain the object. You must then, of course, release it later when you have done with it.
Regards your comment to Matt's answer. Your code is this:
for (NSString * date in dateList)
{
[historyList addObject:[[BIUtility historyForDate:date] retain]];
}
and
+ (NSArray *) historyForDate:(NSString *)date
{
NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease];
}
The first thing you need to know is that collections retain their members, so, in fact, your retain of the historyForDate is unnecessary. You don't want to own that object, historyList does. If it's disappearing, it's probably because historyList itself is being deallocated (because you don't own it) or is nil.
By the way, historyForDate: does nothing with the date. Is that correct?

Objective-C memory management--best practices when returning objects?

Suppose I have a function like this:
- (NSSet *) someFunction {
//code...
return [[[NSSet alloc] initWithObjets:obj1, obj2, nil] autorelease];
}
When I call this function, do I need to do retain/release the return value? I'm assuming I do.
However, what if I don't do autorelease, so someFunction now looks like this:
- (NSSet *) someFunction {
//code...
return [[NSSet alloc] initWithObjets:obj1, obj2, nil];
}
In this case, I'm assuming I need to release but not retain the return value.
My question is, what is the suggested/best practice for these kinds of situations? Is one or the other version of someFunction recommended? Thanks.
You should spend some time reading the Memory Management Programming Guide for Cocoa.
The short is that if you get your reference through a method starts with 'alloc' or 'new' or contains 'copy', you own the reference and do not have to retain it. You do have provide for its release, either through a direct release or through using autorelease.
If you get a reference any other way (through a class method or what-have-you), you do not own a reference, so you don't have to release. If you want to keep a reference, you have to retain it.
Over-all, it is really quite simple and effective.
Hmm...
Normally, I follow this "way".
+ (id)MyObj {
return [[[MyObj alloc] init] autorelease];
}
Releasing the object prior to returning it, the object will be deallocated before it reaches the calling object. This will produce an error. Avoid this error by using a autorelease pool instead. Originally introduced to me by Scott Stevenson of Theocacao. It's his and many, preferred way for Obj-C 1.0.
The only reason you should do the code in the second example is if your method name begins with new, alloc, create, copy, or something like that.
Otherwise you are responsible for releasing (or autoreleasing) any object you allocate. The first example is the correct way to do most things.
The calling function should retain the value if it wants it to persist past the functions scope, but it is then responsible for releasing it at some later point.