views:

523

answers:

3

Say you have a method that returns a newly generated NSArray instance that is built internally with an NSMutableArray. Do you always do something like this:

- (NSArray *)someArray {
    NSMutableArray *mutableArray = [[NSMutableArray new] autorelease];
    // do stuff...
    return [NSArray arrayWithArray:mutableArray];  // .. or [[mutableArray copy] autorelease]
}

Or do you just leave the mutable array object as-is and return it directly because NSMutableArray is a subclass of NSArray:

- (NSArray *)someArray {
    NSMutableArray *mutableArray = [[NSMutableArray new] autorelease];
    // do stuff...
    return mutableArray;
}

Personally, I often turn a mutable array into an NSArray when I return from methods like this just because I feel like it's "safer" or more "correct" somehow. Although to be honest, I've never had a problem returning a mutable array that was cast to an NSArray, so it's probably a non-issue in reality - but is there a best practice for situations like this?

+5  A: 

It's very common to return an NSMutableArray cast as an NSArray. I think most programmers would realize that if they downcast an immutable object and mutate it, then they're going to introduce nasty bugs.

Also, if you have an NSMutableArray ivar someMutableArray, and you return [NSArray arrayWithArray:someMutableArray] in a KVC accessor method, it can mess up KVO. You'll start getting "object was deallocated with observers still attached" errors.

Tom Dalling
A: 

NSArray is in fact a class cluster, not a type, anyway. So anywhere you see an NSArray, chances are it's already one of several different types anyway. Therefore the 'convert to NSArray' is somewhat misleading; an NSMutableArray already conforms to the NSArray interface and that's what most will deal with.

CocoaObjects fundamentals

In any case, given that you're returning an array (and not keeping it afterwards, thanks to the autorelease) you probably don't need to worry whether the array is mutable or not.

However, if you were keeping the array, then you might want to do this, to prevent the clients from changing the contents.

AlBlue
There isn't an NSArray protocol. NSMutableArray is a subclass of the NSArray class.
Peter Hosey
Peter,You're absolutely right, it was a mistake on my part - meant 'interface' there. I've updated my answer accordingly.
AlBlue
+8  A: 

I used to do the return [NSArray arrayWithArray:someMutableArray], but I was slowly convinced that it doesn't offer any real benefit. If a caller of your API is treating a returned object as a subclass of the declared class, they're doing it wrong.

[NB: See bbum's caveat below.]

Wevah
I generally agree. However, if the possibility of the calling code mucking about with the returned value can cause serious issues, then defensive copying is a good idea. This is particularly true for framework code.
Quinn Taylor
If the calling code is mutating something your API says should be treated as immutable, they should be doing a `-mutableCopy`. Else, doing it wrong. ;) (Nothing's stopping you from being defensive if you feel you must, though.)
Wevah
The real issue, though, is that if you return a mutable array reference to an array that may be later mutated, the caller receiving an NSArray* may assume the contents never change... and... well... *BOOM*.
bbum
That is very true. In practice I've probably only returned a mutable array only when that array was created in the method itself (and not, say, an instance variable).
Wevah
(I say "probably" because I can't back that up, though I'll be sure to check for cases where I've foolishly not done this.)
Wevah