When does -copy return a mutable object?

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 is important to know that calling -copy on a mutable object returns an immutable version. If you want to copy the mutable object and keep the volatility 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 simply 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 copying, which can be changed! Copying NSMutableArray can return a NSMutableArray , since the source class, but copying any arbitrary NSArray instance will not.

This seems somewhat isolated from 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...

  • When -copy return an immutable object (as expected) and when does it return a mutable object?
  • How do I achieve the intended effect of producing a “frozen” copy of a mutable object that refuses to “freeze”?
+8
objective-c cocoa mutable nsmutableurlrequest
source share
4 answers

I think that you have discovered a big gap between documentation and reality.

NSCopying protocol documentation requirements:

A returned copy is immutable if the consideration of the issue of “immutable and mutable” refers to the receiving entity; otherwise, the exact nature of the copy is determined by the class.

But this is clearly wrong in some cases, as you showed in your examples (and I sent them feedback about this through this documentation page).

But (# 2), in my opinion, it really doesn't matter, and you don't care.

The -copy point is that it will return an object that you can use, with the guarantee that it will behave independently of the original. This means that if you have a mutable object, -copy it and modify the original object, the copy will not see the effect. (In some cases, I think this means that -copy can be optimized so that it does nothing, because if the object is immutable, it cannot be changed in the first place. Maybe I'm wrong. (Now I wonder what the consequences are for dictionary keys because of this, but what is a separate topic ...))

As you saw, in some cases the new object may actually have a mutable class (even if the documentation tells us that it will not). But as long as you do not rely on the fact that it is changed (why should you?), It does not matter.

What should you do? Always treat the -copy result as immutable , as simple as this.

+12
source share

1) When does -copy return an immutable object (as expected) and when does it return a mutable object?

you should always consider it as an immutable option. a modified return type interface should not be used. in addition to optimization, the answer should not matter and should be considered as an implementation detail, if not documented.

obvious case: for a number of reasons, the objc class cluster and class constructs can be complex. returning a mutable copy might just be for convenience.

2) How to achieve the target effect of obtaining a "frozen" copy of a volatile object that refuses to "freeze"?

using a copy constructor of an immutable class is a good way (similar to St3fan's answer). for example copy , this is not a guarantee.

The only reason I can think about why you would like to enforce this behavior is through performance or force access to a limited interface (unless it is academic). if you need performance or a limited interface, then you can just encapsulate an instance of a type that copies at creation and provides only an immutable interface. then you implement the copy through saving (if that is your intention).

alternatively, you can write your own subclass and implement your own copy variant.

final option: many of cocoa mutable / immutable classes - this is purely an interface - you can write your own subclass if you need to provide specific behavior, but this is rather unusual.

perhaps a better description of why this should be followed would be nice - existing implementations are great for the vast majority of developers / use.

+3
source share

Keep in mind that the copy implementation does not exist - each class implements its own. And, as we all know, the Objective-C runtime implementation is a bit loose goose in spots. Therefore, I can say that basically copy returns an immutable version, but there are some exceptions.

(By the way, what this does:

 NSArray *arr = [[NSMutable array] init]; 

?)

+1
source share

The best way to turn an object into mutable is to use the variable constructor. Such as:

 NSArray* array = ...; NSMutableArray* mutableArray = [NSMutableArray arrayWithArray: array]; 

Copy is used to create a copy of the object. Do not change its variability.

-one
source share

All Articles