I read in Cocoa and Objective C: Up and Running that -copy
will always return an immutable object and -mutableCopy
will always return a mutable object:
It’s important to know that calling
-copy
on a mutable object returns an immutable version. If you want to copy a mutable object and maintain mutability in the new version, you must call-mutableCopy
on the original. This is useful, though, because if you want to “freeze” a mutable object, you can just call-copy
on it.
So I have something like this:
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init];
NSLog( @"%@", [req className] ); // NSMutableURLRequest
NSLog( @"%@", [[req copy] className] ); // NSMutableURLRequest
NSLog( @"%@", [[req mutableCopy] className] ); // NSMutableURLRequest
According to this previous answer:
You cannot depend on the result of copy to be mutable! Copying an
NSMutableArray
may return anNSMutableArray
, since that's the original class, but copying any arbitraryNSArray
instance would not.
This seems to be somewhat isolated to NSURLRequest
, since NSArray
acts as intended:
NSArray *arr = [[NSMutableArray alloc] init];
NSLog( @"%@", [arr className] ); // __NSArrayM
NSLog( @"%@", [[arr copy] className] ); // __NSAraryI
NSLog( @"%@", [[array mutableCopy] className] ); // __NSArrayM
So...
-copy
return an immutable object (as expected) and when does it return a mutable object?I think you've uncovered a great rift between documentation and reality.
The NSCopying protocol documentation claims:
The copy returned is immutable if the consideration “immutable vs. mutable” applies to the receiving object; otherwise the exact nature of the copy is determined by the class.
But this is clearly wrong in some cases, as you've shown in your examples (and I've sent feedback to them about this via that documentation page).
But(#2) in my opinion, it doesn't actually matter and you shouldn't care.
The point of -copy
is that it will return an object you can use with the guarantee that it will behave independently of the original. This means if you have a mutable object, -copy
it, and change the original object, the copy will not see the effect. (In some cases, I think this means that -copy
can be optimized to do nothing, because if the object is immutable it can't be changed in the first place. I may be wrong about this. (I'm now wondering what the implications are for dictionary keys because of this, but that's a separate topic...))
As you've seen, in some cases the new object may actually be of a mutable class (even if the documentation tells us it won't). But as long as you don't rely on it being mutable (why would you?), it doesn't matter.
What should you do? Always treat the result of -copy
as immutable, simple as that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With