关于深复制和浅复制
1.先看两者的区别
深复制(深拷贝,内容拷贝,deep copy)
源对象和副本对象是不同的两个对象
源对象引用计数器不变, 副本对象计数器为1(因为是新产生的)
本质是:产生了新的对象
浅复制(浅拷贝,指针拷贝,shallow copy)
源对象和副本对象是同一个对象
源对象(副本对象)引用计数器 + 1, 相当于做一次retain操作
本质是:没有产生新的对象
一句话总结就是:深复制产生了新的对象,浅复制没有产生新对象,而是原对象做了一次retain操作
2.以NSString 和NSMutableString为例做copy 和mutableCopy总结
//string copy 浅复制 NSString *str1 = [NSString stringWithFormat:@"addd"]; NSMutableString *str2 = [str1 copy]; //str1 = 0x7f9cc9c0ef20,count = 2 //str2 = 0x7f9cc9c0ef20, coutn =2 //string mutablecopy 深复制 NSString *str1 = [NSString stringWithFormat:@"addd"]; NSMutableString *str2 = [str1 mutableCopy]; //str1 = 0x7f8583e1c560,count = 1 //str2 = 0x7f8583e1c400, coutn =1 //mutableString copy 深复制 NSMutableString *str1 = [NSMutableString stringWithFormat:@"addd"]; NSMutableString *str2 = [str1 copy]; //str1 = 0x7fbce2f21560,count = 1 //str2 = 0x7fbce2f1ee40, coutn =1 //mutableString mutablecopy 深复制 NSString *str1 = [NSString stringWithFormat:@"addd"]; NSMutableString *str2 = [str1 mutableCopy]; //str1 = 0x7fea5a555d80,count = 1 //str2 = 0x7fea5a538020, coutn =1 NSLog(@"str1 = %p,count = %lu",str1,str1.retainCount); NSLog(@"str2 = %p, coutn =%lu ",str2,str2.retainCount);
从以上代码可以看出:
1.只有是NSString 调用了copy 复制给另一个对象(不论是NSString,或NSMutableString)才是浅复制,其他情况都是深复制;
2. copy : 创建的是不可变副本(很重要)
mutableCopy: 创建的是可变副本
3.分析:由于copy创建对象的不可变性 ,并且调用copy的对象如果是NSString类型,原对象和副本(新)对象都不可变了,
从内存利用率上来讲,他俩就指向同一个内存空间比较合理,也就是新旧两个指针变量都指向原来的对象(内存),
这个对象(内存)的计数器只需加1就皆大欢喜了,这就是所谓浅复制;
一句话:只有源对象和副本对象都不可变时,才是浅复制,其它都是深复制
最后稍微引申下@prpoerty属性中NSString为啥用copy而不用retain:
copy 和 retain 的关键set方法实现大家都该知道:都是先release旧值,再copy 或retain新值,
retain 新值就是把传入的新值计数器加1,然后把对象复值给属性,很明显他俩都指向同一个对象,
外边的对象变了,内部的属性只肯定也跟着变,这对一般的对象还可以,但对NSString对象就不靠谱了:我拿着传进来的对象还没用,外边的NSString就变了,我里边的NSString类型属性也跟着变了,这就出问题了,必须要保证你外边的NSString可以变,但穿进来时是什么就是什么不能再跟着外边变了。
这就需要用到copy的copy过后新对象不会改变的特性了。不管你是可变的还是不可变的NSString传进来,我的set方法里一copy,那么属性就板上定订不会变了
就是这copy新值让人困惑,卧槽啊,不是说copy是浅复