一.深拷贝
源对象和副本对象是不同的两个对象
源对象引用计数不变,副本对象计数器为1(因为是新产生的)
至少有一层是对象复制
二.浅拷贝
源对象和副本对象是同一个对象
源对象(副本对象)引用计数器+1,相当于做一次retain操作
本质:没有产生新的对象
三.完全复制
对于被复制的对象每一层都是对象复制
四.哪些是深拷贝,哪些是浅拷贝
retain:始终是浅复制;返回对象是否可变与被复制的对象保持一致
copy:对于可变对象是深拷贝,返回一个不可变对象
对于不可变对象为浅拷贝,返回一个不可变对象
mutableCopy:始终是深拷贝,始终返回一个可变对象
五:例子
1.NSString中为什么用copy
1)声明2个字符串属性,一个为strong,一个为copy
@interface TestString : NSObject
@property (nonatomic, strong) NSString *strongString;
@property (nonatomic, copy) NSString *copyedString;
@end
2)用一个不可变字符串来为这两个属性赋值
-(void)test{
NSString *str = @"淩凌0";
self.strongString = str;
self.copyedString = str;
NSLog(@"str:%p",str);
NSLog(@"strongString:%p",self.strongString);
NSLog(@"copyedString:%p",self.copyedString);
}
3)输出结果
2015-12-21 14:56:09.335 使用copy[927:68174] strM:0x100004260
2015-12-21 14:56:09.336 使用copy[927:68174] strongString:0x100004260
2015-12-21 14:56:09.336 使用copy[927:68174] copyedString:0x100004260
结论:不管是strong还是copy属性的对象,其指向的地址都是同一个,为string指向的地址。如果我们换作MRC环境,打印string的引用计数的话,会看到其引用计数值是3,即strong操作和copy操作都使原字符串对象的引用计数值加了1。
4)将NSString改为NSMutableString
-(void)test{
// NSString *str = @"淩凌0";
NSMutableString *strM = [NSMutableString stringWithString:@"淩凌0"];
self.strongString = strM;
self.copyedString = strM;
NSLog(@"strM:%p",strM);
NSLog(@"strongString:%p",self.strongString);
NSLog(@"copyedString:%p",self.copyedString);
}
5)打印结果
2015-12-21 14:49:10.860 使用copy[907:65503] strM:0x100206ed0
2015-12-21 14:49:10.861 使用copy[907:65503] strongString:0x100206ed0
2015-12-21 14:49:10.861 使用copy[907:65503] copyedString:0x100207020
结论:此时copy属性字符串已不再指向string字符串对象,而是深拷贝了string字符串,并让_copyedString对象指向这个字符串。在MRC环境下,打印两者的引用计数,可以看到string对象的引用计数是2,而_copyedString对象的引用计数是1。
最后:
一般我们将对象声明为NSString类型时,都不希望它改变,所以大多数情况下,使用copy,以免因可变字符串的修改导致一些非预期问题