Reputation: 8546
- (NSArray *)map:(id (^)(id))block {
NSEnumerator * enumerator = self.objectEnumerator;
NSMutableArray * array = [NSMutableArray array];
id obj;
while ((obj = enumerator.nextObject)) {
[array addObject:(block(obj) ?: [NSNull null])];
}
return array (NSMutableArray *); or return array.copy (NSArray *)
}
This is a category on NSArray
Upvotes: 2
Views: 2139
Reputation: 66242
From Receiving Mutable Objects:
Use Return Type, Not Introspection
To determine whether it can change a received object, the receiver of a message must rely on the formal type of the return value. If it receives, for example, an array object typed as immutable, it should not attempt to mutate it. It is not an acceptable programming practice to determine if an object is mutable based on its class membership.
[…]
You should not make assumptions about whether an object is mutable based on class membership. Your decision should be guided solely by what the signature of the method vending the object says about its mutability. If you are not sure whether an object is mutable or immutable, assume it’s immutable.
Generally speaking:
If your caller is following these guidelines, just return the mutable array since it's slightly cheaper, and the caller won't mutate it.
If you're not sure whether caller might not follow these guidelines, and you want to code defensively, return an immutable copy using array.copy
.
Specific to this case, it doesn't matter, since even if the caller mutates it, you'll never use that array instance ever again.
Upvotes: 6
Reputation: 2911
In most cases there is no need to create a copy since you aren't holding another reference to array
outside of the method.
One thing to consider however is that under the hood, these objects are different. If you print the objects in the debugger, you will find that one is __NSArrayM
while the other __NSArrayI
.
The compiler will protect you by not letting you call mutational messages on the returned NSArray
directly, but that doesn't stop you from simply casting an __NSArrayM
into an NSMutableArray
or performing mutational selectors on the object and bypassing the compiler. Calling a mutational message on an __NSArrayI
will cause the app to crash so if you want to guaranty this safety, calling copy
on the return is the way to go.
Upvotes: 0
Reputation: 46578
In this case, you do not need to copy.
The array object is created locally, so it can't be modified unexpectedly by something else.
The interface only specify it returns NSArray *
, so as long as it return a kind of NSArray *
, it satisfied the requirement. Whether it return MyCustomArray *
or NSMutableArray *
is purely implementation details, it won't have any effect in caller point view.
However, if the array object is shared, you do need to return a copy of it. Otherwise the immutable assumption on NSArray
may be broken and cause unexpected behaviour.
Upvotes: 3
Reputation: 90531
In the given code, the mutable array is created just to be returned. It isn't held on an ongoing basis by anything else. Therefore, there's no danger in returning it directly.
There are two main dangers in returning a mutable array that continues to be held by the returning code:
So, if the method is returning a mutable array that it continues to hold a reference to, it should probably return a copy.
Upvotes: 3
Reputation: 15015
It depends on your return type of the method. If your return type is immutable use copy or else mutableCopy.
Upvotes: 0