迷惑的copy

183 阅读2分钟

使用对象时经常需要拷贝它,而类只有实现NSCoping协议,才能支持拷贝操作。

confused

//NSCopying协议方法,
//参数zone,为默认区,
- (id)copyWithZone:(nullable NSZone *)zone;
  • 若想某个类支持拷贝功能(不可变immutableCopy的拷贝),只需声明该类遵从NSCoping协议,并实现上述方法即可。
//NSMutableCopying 协议方法
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
  • 实现上述方法,可以让对象进行一份可变版本的拷贝,即NSString -> NSMutableString, NSArray -> NSMutableArray

copy or mutableCopy

  1. copy 执行的一定是不可变版本的拷贝,哪怕NSMutableArray, NSMutableString 这类可变对象,进行copy操作,返回对象的也是不可变的,返回对象类型本质为 NSArray, NSString 类型

  2. mutableCopy 执行的是可变版本的拷贝,不论对象是可变的对象(NSMutableString, NSMutableArray),还是不可变对象(NSArray, NSString),执行mutableCopy方法后返回对象都是可变的。

  3. Foundation 框架中的所有collection类在默认情况下都执行浅拷贝,即,只拷贝容器对象本身,而不复制其中数据。

  4. 没有专门定义深拷贝的协议,绝大多数遵从NSCoping协议的对象执行的都是浅拷贝。除非文档说明是深拷贝,或者自定义方法来实现。

  5. 针对NSString源码 可以确定,copy操作是浅拷贝,跟retain一样,mutableCopy是深拷贝,重新生成了一个新对象,是NSMutableString类型

     /* NSCopying methods */
    
     - (id)copyWithZone:(NSZone *)zone
     {
         if (NSStringClass == Nil)
             NSStringClass = [NSString class];
         
         return RETAIN(self);
         // return [[NSStringClass allocWithZone:zone] initWithString:self];
     }
     
     /* NSMutableCopying methods */
     
     - (id)mutableCopyWithZone:(NSZone*)zone
     {
         return [[NSMutableString allocWithZone:zone] initWithString:self];
     }
    
  6. NSMutableString源码只有copy方法,返回的是NSString类型,重新生成了一个新的对象,是深拷贝,执行mutableCopy,实际是调用父类NSStringmutableCopy方法。

     -(id)copy {
     	return [[NSString alloc] initWithString:self];
     }
    
     -(id)copyWithZone:(NSZone*)zone {
         return [[NSString allocWithZone:zone] initWithString:self];
     }
    

总结:

1. 只有实现NSCoping协议,才能执行copy操作

2. 如果自定义的对象分为可变与不可变版本,需要同时实现NSCopingNSMutableCoping协议

3. 复制对象一般尽量执行浅拷贝

4. 如果对象需要深拷贝,可考虑新增一个专门执行深拷贝的方法