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

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

屏幕快照.png

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

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

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


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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、对象拷贝有两种方式:浅复制和深复制。顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针;深复制是直接...
    滴答大阅读 789评论 0 2
  • 1.什么情况使用关键字copy? 相比 assign 有什么不同? (1).在 ARC 中,在有可能出现循环引用的...
    爱赚钱的依米阅读 2,069评论 0 22
  • 浅拷贝:拷贝容易本身,返回一个对象,指向相同的内存地址. 深层复制:拷贝容器本身,返回一个对象,指向不同的内存地址...
    CoderShmily阅读 7,060评论 5 9
  • 看完很多同学给我的留言,我只想说一句:孟老师很忧伤,真的很忧伤。因为太多同学不知道该如何提问。所以我决定今天在回答...
    孟享专栏阅读 322评论 0 3
  • 今天的泪水,会是你明天的成长;今天的伤痕,会是你明天的坚强!有些路,只能一个人走,路上的艰辛,只有自己知道。不悲过...
    Nadirou阅读 127评论 0 0