views:

54

answers:

1

I know you shouldn't use this to decide whether or not to change an array:

if ([possiblyMutable isKindOfClass:[NSMutableArray class]])

But say I'm writing a method and need to return either an NSMutableArray or an NSArray, depending on the mutability of possiblyMutable. The class using my method already knows whether or not it's acceptable to change the returned array. Whether or not it's acceptable to change the returned array directly correlates with whether or not it's acceptable to change possiblyMutable.

In that specific case, is this code safe? It seems to me that if it's not acceptable to change the array, but we accidentally get a mutable array, it's ok, because the class using my method won't try to change it. And if it is acceptable to change the array, then we will always get possiblyMutable as an NSMutableArray (though this is the part I'm not entirely clear on).

So... safe or not? Alternatives?

+4  A: 

No. Not safe at all.

If you do:

NSMutableArray * ma = [NSMutableArray arrayWithObject:@"foo"];
NSArray * aa = [NSArray arrayWithObject:@"foo"];

NSLog(@"Mutable: %@", [ma className]);
NSLog(@"Normal: %@", [aa className]);

Then you get:

2010-04-05 13:17:26.928 EmptyFoundation[55496:a0f] Mutable: NSCFArray
2010-04-05 13:17:26.956 EmptyFoundation[55496:a0f] Normal: NSCFArray

You also can't do:

NSLog(@"Mutable add: %d", [ma respondsToSelector:@selector(addObject:)]);
NSLog(@"Normal add: %d", [aa respondsToSelector:@selector(addObject:)]);

Because this logs:

2010-04-05 13:18:35.351 EmptyFoundation[55525:a0f] Mutable add: 1
2010-04-05 13:18:35.351 EmptyFoundation[55525:a0f] Normal add: 1

The only ways to guarantee you have a mutable array are to take the -mutableCopy of an existing array or if the return type of a function/method guarantees the array will be mutable.

Dave DeLong
To be more explicit, there should not be a situation where you treat mutable arrays and normal arrays differently. To do it, you'd have to specifically pass around information about the array's mutability from the moment it's created, and that is a fragile design nightmare. Otherwise, you should always either copy or mutableCopy the array depending on which you want.
Chuck
How does NSCoding work, then? Say I have an array of mutable arrays, and I encode it. Upon decoding, do I need to step through the array and send `mutableCopy` to every one of the subarrays?
andyvn22
No, NSCFArray tracks its own mutability internally (as a private implementation detail). NSCoding will do the right thing, since NSCFArray gets to define its own encoding and decoding.
Barry Wark
Double +1. You should *never* need to design code in this way. Make a mutableCopy if you want/need a mutable copy. You may have to return a new array to the caller in this case.
Barry Wark