美文网首页iOS Developer
iOS深拷贝与浅拷贝

iOS深拷贝与浅拷贝

作者: watermelon_lp | 来源:发表于2017-03-02 21:48 被阅读67次

    大家好,我是西瓜,现居广州。在今年想要回顾梳理一下OC的相关知识点。今天就先从基础但不简单的深拷贝与浅拷贝开始吧。

    我们从一道当初很出名的面试题开始我们今天的学习:

    为什么NSString要用copy修饰而不是strong?

    我们先看第一个问题,为什么NSString要用copy而不用strong。但凡有iOS基础的同学们都知道,NSString是一个对象,而对象就是用strong,保证强引用不被释放。与strong属于同一层级的修饰词还有weak,assign,copy。weak和assign可以轻松的理解,唯独让人困惑的就是copy的用法。

    接下里我们先看一段代码:

    @interface Person : NSObject
    
    @property (nonatomic, copy) NSArray *array_copy;
    @property (nonatomic, strong) NSArray *array_strong;
    
    @end
    
        Person *p1 = [[Person alloc] init];
    
        NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1", nil];
        
        p1.array_copy = array;
        p1.array_strong = array;
        
        NSLog(@"addObject之前 array 地址%p 值%@", array, array);
        NSLog(@"addObject之前 array_strong 地址%p 值%@", p1.array_strong, p1.array_strong);
        NSLog(@"addObject之前 array_copy 地址%p 值%@", p1.array_copy, p1.array_copy);
        
        [array addObject:@"2"];
        
        NSLog(@"addObject之后 array 地址%p 值%@", array, array);
        NSLog(@"addObject之后 array_strong 地址%p 值%@", p1.array_strong, p1.array_strong);
        NSLog(@"addObject之后 array_copy 地址%p 值%@", p1.array_copy, p1.array_copy);
    

    打印结果如下:

    2017-02-27 20:48:31.750 test[49360:1849602] addObject之前 array 地址0x60800005cc20 值(
        1
    )
    2017-02-27 20:48:31.750 test[49360:1849602] addObject之前 array_strong 地址0x60800005cc20 值(
        1
    )
    2017-02-27 20:48:31.751 test[49360:1849602] addObject之前 array_copy 地址0x608000011d30 值(
        1
    )
    2017-02-27 20:48:31.751 test[49360:1849602] addObject之后 array 地址0x60800005cc20 值(
        1,
        2
    )
    2017-02-27 20:48:31.751 test[49360:1849602] addObject之后 array_strong 地址0x60800005cc20 值(
        1,
        2
    )
    2017-02-27 20:48:31.751 test[49360:1849602] addObject之后 array_copy 地址0x608000011d30 值(
        1
    )
    

    有基础的同学看看这段代码,然后仔细思考一番应该就能想通为什么是这个打印结果了。

    不过没事,下面我会来一一讲解。
    我们首先创建了一个可变数组叫array,接着把array赋值给Person的两个属性,这两个属性都是不可变数组,唯一的区别就是一个用copy修饰,一个用strong修饰。

    接着我们分别打印arrayarray_strongarray_copy的值和地址,发现三个数组的值都是一样的,但array_copy的地址却和其他两个数组不相同,这是为什么呢?

    最后我们给array可变数组添加一个字符串,再次打印,发现arrayarray_copy无论是地址还是值都一样,但array_strong却独树一帜,无论是值还是地址,都和其它二位不相同。

    其中p1.array_copy = array由于array_copycopy修饰的,所以这段代码会产生类似于p1.array_copy = [array copy]的效果。

    出现这样的原因就是因为发生了深拷贝和浅拷贝

    通俗来说,指针有变化就是深拷贝,指针无变化就是浅拷贝

    如果把Person中的数组变成NSString,结果也是类似的。这样我们就可以回答第一个问题了:

    NSString使用copy是为了防止被赋值后再被外界所修改

    按道理讲NSArrayNSDictionary这些容器对象也应该使用copy,以防止出现上述例子中出现的问题,但这个说法早就已经过时了。使用copy还是strong完全取决于你的需求。你希望跟随外界改动就用strong,不希望就用copy

    粗略的画了这张图来解释上述例子,不要介意:

    屏幕快照.png

    所以我们可以得出简单的结论

    浅拷贝:一个指针,指向一块内存, 对这块内存进行浅拷贝,其实就是提取了这块内存的地址,把他给另外一个指针类型存放。

    综合来看,内存并未有任何变化,但是现在有两个指针指向它。并且这两个指针存放的值一样,就是这块内存的地址,但是这两个指针本身的内存地址不一样,所以就是两个不同的指针指向同一块内存。


    深拷贝: 一个指针,指向一块内存1,对这块内存1进行深拷贝,首先,我要开辟一块跟这块内存一样大的内存2,然后把内存1里面的值(请注意,这里是值)的复制到内存2里,然后再建一个指针,指向内存2。

    这时候来看,存在两块内存,并且两块内存毫不相干,只是里面的值暂时一样而已。 修改其中一个也不会影响另一个。

    第一次写技术文章,肯定有诸多不足,请多包容。如果有不懂的或者想要技术交流都可以私信我,谢谢大家。

    相关文章

      网友评论

        本文标题:iOS深拷贝与浅拷贝

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