大家好,我是西瓜,现居广州。在今年想要回顾梳理一下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
修饰。
接着我们分别打印array
,array_strong
,array_copy
的值和地址,发现三个数组的值都是一样的,但array_copy
的地址却和其他两个数组不相同,这是为什么呢?
最后我们给array
可变数组添加一个字符串,再次打印,发现array
和array_copy
无论是地址还是值都一样,但array_strong
却独树一帜,无论是值还是地址,都和其它二位不相同。
其中p1.array_copy = array
由于array_copy
是copy
修饰的,所以这段代码会产生类似于p1.array_copy = [array copy]
的效果。
出现这样的原因就是因为发生了深拷贝和浅拷贝。
通俗来说,指针有变化就是深拷贝,指针无变化就是浅拷贝
如果把Person
中的数组变成NSString
,结果也是类似的。这样我们就可以回答第一个问题了:
NSString
使用copy
是为了防止被赋值后再被外界所修改按道理讲
NSArray
,NSDictionary
这些容器对象也应该使用copy
,以防止出现上述例子中出现的问题,但这个说法早就已经过时了。使用copy
还是strong
完全取决于你的需求。你希望跟随外界改动就用strong
,不希望就用copy
。
粗略的画了这张图来解释上述例子,不要介意:
所以我们可以得出简单的结论
浅拷贝:一个指针,指向一块内存, 对这块内存进行浅拷贝,其实就是提取了这块内存的地址,把他给另外一个指针类型存放。
综合来看,内存并未有任何变化,但是现在有两个指针指向它。并且这两个指针存放的值一样,就是这块内存的地址,但是这两个指针本身的内存地址不一样,所以就是两个不同的指针指向同一块内存。
深拷贝: 一个指针,指向一块内存1,对这块内存1进行深拷贝,首先,我要开辟一块跟这块内存一样大的内存2,然后把内存1里面的值(请注意,这里是值)的复制到内存2里,然后再建一个指针,指向内存2。
这时候来看,存在两块内存,并且两块内存毫不相干,只是里面的值暂时一样而已。 修改其中一个也不会影响另一个。
第一次写技术文章,肯定有诸多不足,请多包容。如果有不懂的或者想要技术交流都可以私信我,谢谢大家。