valverij
valverij

Reputation: 4941

Returning NSMutableArray object from a method with an NSArray return value

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:

  1. Return the NSMutableArray directly (as above)

    return returnValue;
    
  2. Return a copy

    return [returnValue copy];
    
  3. Return using NSArray arrayWithArray:

    return [NSArray arrayWithArray:returnValue];
    
  4. 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

Answers (3)

erik
erik

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

user3125367
user3125367

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

Sergey Kalinichenko
Sergey Kalinichenko

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

Related Questions