首页 > 代码库 > 关于copyWithZone 实现拷贝

关于copyWithZone 实现拷贝

最近修复一bug ,进而窥见了copyWithZone(NSZone *)zone

 

该bug 场景是这样的

A 界面展示 一些地址列表,每行对应一个addressModel. 选中行

 

进入 B界面 展示 三行地址详情,分别是别名(如,公司),地址名(如,中关村XX). 其他(。。。) 选中B界面 地址名(中关村XX)

 

进入 C 界面 使用TextFied 输入并 搜索地址,

 

A 进入 B 进入 C 都是在界面跳转时 传递了同一个 addressModel.

 

C界面 搜索并选中地址后 回到 B 界面中,自然显示最新的选中结果(修改了同一个mode,大多数情况下,我们实现传递对象OC 是 用指针,*obj。). 需要在B 界面中 保持地址信息(B 就是编辑地址的界面,如删除,修改),回到A 界面 显示最新的修改结果。

 

但是在B 中修改了 地址信息 没有保持 直接返回 A 界面。这时 A中列表没有刷新,但实际上A界面内存中 该行对应Model 已经修改为B 界面中没有保持 的结果。 重复进入B 界面 ,傻眼了,显示了没有保持的 错误地址信息。

 

该bug 有不同解决思路。但本质应该是这样的。 A 中只需要给B 一个拷贝的对象,B 去修改或 不修改 在没有保存 同步到服务器 之前。返回A  没有任何影响。(B 中仅仅是个 备份)。

 

So,下面进入正题。如何 重写 copyWithZone(NSZone *)zone 实现 拷贝或 深拷贝。

 

首先,你要让自定义类实现NSCopying 或 NSMutableCopying  对应的是可变对象 和 非可变对象copy 协议。

 

CustomMode:NSObject<NSCopying>{

   NSString * a;

   int  c;

}

……..

如果你的父类没有实现<NSCopying>,重写

-(id)copyWithZone(NSZone *)zone{

   CustomMode *custom = [[[self class]  copyWithZone:zone]  init];

   Custom ->_a = [_a copyWithZone:zone]; 

   Custom -> _c = _c;//不是对象的 直接赋值

   Return custom;

}实现深拷贝。在ARC 下。

如果你的父类实现了<NSCopying>,并重写了

-(id)copyWithZone(NSZone *)zone

 

CustomSuper:NSObject<NSCoping>

 

-(id)copyWithZone(NSZone *)zone{

   CustomSuper *custom = [[[self class]  copyWithZone:zone]  init];

   Return custom;

}

 

CustomMode:CustomSuper

 

-(id)copyWithZone(NSZone *)zone{

CustomModel *custom = [super copyWithZone:zone];

….

Return custom;

}

 

否则 直接向Custom 对象发copy 消息会蹦。

 

以为大功告成,但撇了一眼这篇文章 就不淡定了。

http://robnapier.net/implementing-nscopying

 

结论是。Objc_object 是一个结构体的实例。我们可以让所有的实例变量的快速内存拷贝为当前类。该结构的其余部分可能已被初始化为NULL如常。如果这听起来很复杂,应该是简单,只需调用class_getInstanceSize()为你的父类。添加它为self 去得到你第一个实例偏移。和memcpy()为您class_getInstanceSize()减去你的超类的字节数。然后,你可以清理你自己的保留计数不搞砸了你的子类。更妙的是,多个子类可以使用这个快速复制,而不会影响对方,相比NSCopyObject(),它只能通过顶层类的使用。

比如父类中实现 子类的深拷贝:

- (id)copyWithZone:(NSZone *)zone {      id copyInstance = [[[self class] allocWithZone:zone] init];      size_t instanceSize = class_getInstanceSize([self class]);      memcpy((__bridge voidvoid *)(copyInstance), (__bridge const voidvoid *)(self), instanceSize);      return copyInstance;  }  

 

 

参见:

实现NSCopying(或NSCopyObject()是有害的)

http://robnapier.net/implementing-nscopying

http://blog.csdn.net/garychow520/article/details/20548383

 http://stackoverflow.com/questions/12572999/what-is-the-operator-doing-in-copywithzone?rq=1

http://stackoverflow.com/questions/4089238/implementing-nscopying

 

关于copyWithZone 实现拷贝