Reputation: 4941
When returning an NSArray
(or NSDictionary
, etc.) from a method that builds the array on the fly using an NSMutableArray
, what is the standard way to do this and avoid random memory leaks when using ARC?
For example, let's say we had some class with a list of names, and we wanted to manually filter and grab all of the names that started with a given letter:
- (NSArray *)getNamesByFirstLetter:(NSString *)firstLetter
{
NSMutableArray *returnValue = [[NSMutableArray alloc] init];
for(id item in self.names)
{
if([item hasPrefix:firstLetter])
{
[returnValue addObject:item];
}
}
return returnValue; // just return the above array
}
When it comes to returning the value, I can think of four possible ways to do it:
Return the NSMutableArray
directly (as above)
return returnValue;
Return a copy
return [returnValue copy];
Return using NSArray arrayWithArray
:
return [NSArray arrayWithArray:returnValue];
Create an NSArray
, manually set the NSMutableArray
to nil
:
NSArray *temp = [NSArray arrayWithArray:returnValue]; // could use [returnValue copy] here too
returnValue = nil;
return temp;
When a program is using ARC, is there any real difference between these four methods, or does it just come down to personal preference?
Also, besides possible memory leaks, are there any other implications when using one method over another?
Note, if this is a duplicate, let me know, and I'll take the question down. I tried searching, but had a hard time trying to condense the issue down to a few search terms.
Upvotes: 11
Views: 5478
Reputation: 106
All four of your options are fine with ARC enabled (i.e. none of your proposed solutions will cause a memory leak).
However, the 4 solutions you outline do slightly different things. Number 1 will return an NSMutableArray
, which likely won't cause problems because NSMutableArray
will respond to all the same messages as NSArray
(but the returned object will be mutable, which you might not want).
There is a subtle difference between option 2 and options 3 & 4 (which are identical under ARC). If returnValue
is nil
, option 2 will return nil
, but options 3 & 4 will return an empty NSArray
. (Either behavior might be desirable; you should decide how you want this method to behave). Also, -copy
is likely a faster operation than +arrayWithArray
.
I would go with option 2.
Upvotes: 9
Reputation: 3000
One thing beside that there is no leaks in the given example, is that everyone knows that NSArray may be mutable. If you get it as result of method call, it is up to you whether you copy it or use as-is, being ready for it to change anytime. That's why immutable properties are often declared as copy instead of strong. Assigning mutable value to that property will do real copy, and assigning immutable value is cheap.
tl;dr: just return returnValue, it is OK.
Upvotes: 0
Reputation: 726539
First thing first: none of the approaches that you discuss would result in a memory leak under ARC. Moreover, approach number four does not require you to set returnValue
to nil
- the compiler is smart enough to take care of the returnValue
on its own. This makes the approach number four to be exactly the same as the number three.
Additionally, calling a copy
on returnValue
is the same as creating a new array from its content, so the second approach is the same as the last two.
This leaves us with two approaches - the first one, and the second/third/forth. The major differences between them in what the user would be able to do with the array that he gets back from your method. The first approach let the user modify the array; the last three do not. Deciding on which behavior you would prefer is up to you.
Upvotes: 3