美文网首页
copy 和 mutablecopy

copy 和 mutablecopy

作者: 纵横而乐 | 来源:发表于2017-04-08 16:56 被阅读79次

    copy和mutablecopy 源于对数据的复制需求,对于对象类型的数据来说,区别于直接持有这个数据对象的方式,复制可以确保所复制出来的对象不受源对象数据修改的影响。

    而oc中的copy对于数值类型,对象类型,及容器数据对象类型都有不同的门道
    对于数值类型来说,copy意味着对数据的直接复制,而对于对象类型来说,有浅复制和深复制的区别
    在详细讨论深浅复制及copy与mutableCopy之前,先来看几个例子:

    NSArray的copy和mutableCopy

    以容器类NSArray及NSMutableArray为例

    NSMutableArray* ma1 = [[NSMutableArray alloc] initWithObjects:@"v1",@"v2", nil];
    __unused NSMutableArray* ma2 = [ma1 mutableCopy];
    __unused NSArray* ca1 = [ma1 copy];
    __unused NSArray* ca2 = [ca1 copy];
    _ca3 = [ca1 copy];          // ca3定义为属性 @property (copy) NSArray* ca3;
    [ma1 removeObjectAtIndex:1];    
    __unused CFIndex i = CFGetRetainCount((__bridge CFArrayRef)ca1);
    

    ca1与ca2及_ca3持有同一个数组,且i值为3,而最终ma1值为 {@"v1"},ca1,ca2,_ca3值为{@"v1",@"v2"}

    NSString的copy

    int e = 1;
    NSString* oa1 = [NSString stringWithFormat:@"abc%d",e];
    __unused NSString* ca1 = [oa1 copy];
    __unused NSString* ca2 = [oa1 copy];
    __unused CFIndex i = CFGetRetainCount((__bridge CFStringRef)oa1);
    

    oa1,ca1,ca2都指向同一个字符串对象,但比较奇怪的是i 值为9223372036854775807,可见其引用计数非法,编译器在编译阶段已经生成了字符串并为其分配了空间,而如果调整成这样

    int e = arc4random();
    NSString* oa1 = [NSString stringWithFormat:@"abc%d",e];
    __unused NSString* ca1 = [oa1 copy];
    __unused NSString* ca2 = [oa1 copy];
    __unused CFIndex i = CFGetRetainCount((__bridge CFStringRef)oa1);
    

    则i 值为4

    深浅拷贝

    根据object copying(apple 文档), 支持复制的对象需要实现NSCopying,若有需要还可实现NSMutableCopying,即可以向其发送copy甚至mutableCopy消息。
    而深浅复制的不同在于,虽然对于标量数据来说,深浅复制都会对其进行复制,而对于对象类型来说,深复制是完全复制出一个同样的对象,而浅复制则只复制对象的引用,比如像前面NSArray例子中那样只是引用计数增加1

    深拷贝和浅拷贝与copy及mutableCopy

    需要注意的是 深拷贝和浅拷贝与copy及mutableCopy并没有一对一的关系,并不是说copy即是浅拷贝,mutableCopy即是深拷贝。因为copy消息返回值其实是对应的NSCopying方法 copyWithZone:的返回值,如果覆盖这个方法,你可以仅仅简单地返回原对象,也可以自己实现深拷贝,或者不算深也不算浅的拷贝,这取决于你自己的需求。
    在开发中除了自己编写的类,很多情况下是对ios系统类的copy与mutableCopy的使用,了解它们的一些特性也是copy与mutableCopy这个点中很重要的部分。
    像前面NSArray的例子,一般来说mutableCopy会进行深拷贝,即会生成新的对象,不管原对象是否是mutable对象,而如果原对象是mutable对象,则copy也会进行深复制,其结果一定是返回一个immutable对象。

    嵌套对象

    所谓的深复制其实也会两种,一种是对于嵌套的对象同样进行深复制,另一种是对于嵌套的对象进行浅复制

    NSMutableDictionary* oa1 = [@{@"k1":@"v1",@"k2":[@"v2" mutableCopy]} mutableCopy];
    __unused NSDictionary* ca1 = [oa1 copy];
    __unused NSDictionary* ca2 = [ca1 copy];
    __unused CFIndex i = CFGetRetainCount((__bridge CFDictionaryRef)ca1);
    [[oa1 objectForKey:@"k2"] appendString:@"append"];
    

    比如这个例子中,oa1虽然与ca1及ca2并不是同一个对象,但其中的元素其实是指向的同一个对象,因为最终ca1的值为

    {
        k1 = v1;
        k2 = v2append;
    }
    

    也就是说在容器对象这个层面上,深拷贝已经生成了新的容器对象,但对容器对象中包含的子对象却还只是进行了浅复制。

    相关文章

      网友评论

          本文标题:copy 和 mutablecopy

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