美文网首页
关于copyWithZone 实现拷贝 及copy mutabl

关于copyWithZone 实现拷贝 及copy mutabl

作者: 真爱要有你才完美 | 来源:发表于2018-01-04 10:46 被阅读147次

    最近修复一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 中仅仅是个 备份,及减少上下文 之间的依赖,也是copy 的本质作用)。

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

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

    CustomMode:NSObject{

       NSString * a;

       int  c;

    }

    ……..

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

    -(id)copyWithZone(NSZone *)zone{

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

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

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

       Return custom;

    }实现深拷贝。在ARC 下。

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

    -(id)copyWithZone(NSZone *)zone

    CustomSuper:NSObject

    -(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 { 

        idcopyInstance = [[[selfclass] allocWithZone:zone] init]; 

        size_t instanceSize = class_getInstanceSize([selfclass]); 

        memcpy((__bridge voidvoid *)(copyInstance), (__bridgeconstvoidvoid *)(self), instanceSize); 

        return copyInstance; 

    延伸Copy 和 metableCopy  详解:

    http://www.cnblogs.com/ydhliphonedev/archive/2012/04/27/2473927.html

    简单说就是  copy 返回不可变对象,mutableCopy 返回可变对象。但 在程序中  

    对于 不可变对象(如:常量 。NSString *a = @"abc".)copy 返回不可变对象,常量本来就是不可变的。如果重新分配内存,有点浪费啦。

    所有 copy 后的对象 和a 都指向 内存中的一块保存常量的内存块。 及浅拷贝,此时指向常量的地址 *a 引用计数为2。mutableCopy 返回可变对象,所以会赋值内容。及深拷贝。

         1.对不可变对象(常量)copy 是浅拷贝, mutableCopy 是深拷贝。

    对于可变对象 copy 返回不可变对象, 所以会拷贝内容,其内容不可变。 metableCopy 也会拷贝内容,但内容是可变的。 都是深拷贝。

        2.对可变对象 copy 和 mutableCopy 都是 深拷贝。

    关于容器实现copy 或 mutaubleCopy ,容器内元素默认都是 指针拷贝,

    除非 使用

    NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:

    [NSKeyedArchiver archivedDataWithRootObject: array]];

    实现元素的 内容拷贝 ,深拷贝。

    可变容器和不可变容器 本事也是遵循 上面结论的。这里会有不可变容器内 有可变元素  不可变元素 共存的情况,可变容器也一样。

        NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];

    copy 和mutableCopy  对容器本事是深拷贝。其内部元素是指针拷贝。

    参见:

    实现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 实现拷贝 及copy mutabl

          本文链接:https://www.haomeiwen.com/subject/rrzlnxtx.html