iOS深拷贝与浅拷贝

大家好,我是西瓜,现居广州。在今年想要回顾梳理一下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

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

iOS深拷贝与浅拷贝_第1张图片
屏幕快照.png

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

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

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


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

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

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

你可能感兴趣的:(iOS深拷贝与浅拷贝)