Person* p = [Person new];
这是oc中最常见的一句代码,它指的是有一个Person对象存在于堆区,p是一个指向这个对象的指针,如下图所示,它的value是堆区的一个地址。而这个指针的地址是&p。

再来看这样一句代码:
NSLog(@"%p",arr);打印出地址值0x2823333c0,这个地址所在的空间里存了一个这样的结构@[address],里边的address 是对象在堆区的地址。
理解以上两个概念以后,我们再来理解copy的概念。 先说两个基础概念:
浅复制:不拷贝对象本身,仅仅是拷贝指向对象的指针
深复制:是直接拷贝整个对象内存到另一块内存中
再说数组的拷贝,分为NSArray和NSMutableArray. 还是这句代码
NSArray *arr = [NSArray arrayWithObjects:p, nil]
<br> id arr_copy = [arr copy];
<br>id arr_mutableCopy = [arr mutableCopy];
打印结果如下:

那么假如又这样一个需求:
NSArray *arr = [NSArray arrayWithObjects:p, nil];
id arr_mutableCopy = [arr mutableCopy];
要求arr中p的改变,不影响arr_mutableCopy中p的改变,需要怎么实现?
只能让P实现NSCopying协议,并且要深拷贝,然后pcopy一个新的对象,放进arr_mutableCopy里。
再来说一说
NSArray *arr = [NSArray arrayWithObjects:p, nil]
<br> id arr_copy = [arr copy];
<br>id arr_mutableCopy = [arr mutableCopy];
打印如下:

刚刚说到自定义对象的拷贝,需要注意一下这点: @property (nonatomic, copy) Person *per; 自定义person类没有遵循NSCopying协议,所以会crash。
2019-10-23 10:27:18.341759+0800 图片存取[4774:1961611] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person copyWithZone:]: unrecognized selector sent to instance 0x2821a49c0'
关于字符串的copy是类似的。
NSString * str = @"str";
NSString * copyStr = [str copy];
NSLog(@"%p,%p",str,copyStr);
NSString使用copy是指针拷贝,并没有生成新的对象,原因很明显,因为之前的对象也是不可变对象。
NSMutableString * mutableStr = [NSMutableString stringWithFormat:@"mutableStr"];
id mutableStr_copy = [mutableStr copy];
可变字符串的拷贝是深拷贝,重新生成了一个新的对象,新的字符串是个不可变字符串,这样就保证了新对象的修改不会影响旧对象。
这也是为什么属性中一个不可变字符串要用copy修饰,如果是赋值是一个NSString对象,用strong或者copy都是一样的,但是如果赋值的是一个NSmutableString的话,如果用strong,那就会出问题,
NSMutableString * mutableStr = [NSMutableString stringWithFormat:@"mutableStr"];
self.string = mutableStr;
这时self.string会随着mutableStr的修改而修改,这显然不是我们想要的效果。
总结:
1.对于NSString,NSArray等不可变的属性,用copy修饰,对于NSmutableString,NSMutablearray等可变的数组,用strong指针引用就可以了。
2.copy出来的数据都是不可变的。对于不可变数据nsarry,nsstirng等他是指针拷贝,而对于NSmutablearray则是深拷贝。而mutablecopy出来的数据都是可变的。而且都是深拷贝。