1.浅拷贝
所谓的浅拷贝,就是指只是将对象内存地址多了一个引用,也就是说,拷贝结束之后,两个对象的值不仅相同,而且对象所指的内存地址都是一样的。
2.单层深拷贝
对于不可变的容器类对象(如NSArray、NSSet、NSDictionary)进 mutableCopy 操作,内存地址发生了变化,但是其中的元素内存地址并没有发生变化,属于单层深拷贝。 对于可变集合类对象(如NSMutableArray、NSMutableSet、NSMutableDictionary),不管是进行 copy 操作还是 mutableCopy 操作,其内存地址都发生了变化,但是其中的元素内存地址都没有发生变化,属于单层深拷贝。
3.深拷贝
所谓深拷贝,就是指拷贝一个对象的具体内容,拷贝结束之后,两个对象的值虽然是相同的,但是指向的内存地址是不同的。两个对象之间也互不影响,互不干扰。
@property (nonatomic, strong) NSArray *array0; // 不推荐写法
@property (nonatomic, copy) NSArray *array1; // 推荐写法
@property (nonatomic, strong) NSMutableArray *array2; // 推荐写法
@property (nonatomic, copy) NSMutableArray *array3; // 错误写法
像NSArray,NSDictionary,NSMString等推荐使用copy修饰, 如果传递的是 NSArray 对象,则只是对原先对象的一份强引用(应该是编译器优化的),但是如果传递的是 NSMutableArray 对象,则是对原先对象的一次“单层深拷贝”,生成的 NSArray 对象是一份新内存地址的对象,但是其中的元素还是原先的。
retain:始终是浅复制。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。
copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制, 引用计数每次加一。始终返回一个不可变对象。
mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。
因为⽗父类指针可以指向⼦子类对象,使⽤用 copy 的⽬目的是为了了让本对象的属性不不受外界影响,使⽤ copy ⽆无论给我传⼊是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
如果我们使用是 strong ,那么这个属性就有可能指向⼀个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
copy 此特质所表达的所属关系与 strong 类似。然而设置⽅法并不保留新值,⽽是将其“拷贝” (copy)。 当属性类型为 NSString 时,经常⽤此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个 NSMutableString 类的实例。这个类是NSString 的⼦类,表示一种可修改其值的字符串,此时若是不拷⻉字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷⻉⼀份。
1. 对⾮非集合类对象的copy操作:
在⾮集合类对象中:对 immutable 对象进行 copy 操作,是指针复制,mutableCopy操作时内容复制;
对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。
⽤代码简单表示如下:
[immutableObject copy] // 浅复制
[immutableObject mutableCopy] //深复制
[mutableObject copy] //深复制
[mutableObject mutableCopy] //深复制
⽐如以下代码:
NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
NSString *stringCopy = [string copy];
查看内存,会发现 string、stringCopy 内存地址都不一样,说明此时都是做内容拷贝、深拷贝。即使你进行如下操作:
[string appendString:@"origion!"]
stringCopy 的值也不会因此改变,但是如果不使用 copy,stringCopy 的值就会被改变。 集合类对象以此类推。
所以,用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy 关键字,是
因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷⻉一份。
2、集合类对象的copy与mutableCopy
集合类对象是指 NSArray、NSDictionary、NSSet ... 之类的对象。下⾯先看集合类
immutable对象使⽤用 copy 和 mutableCopy 的⼀个例子:
NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
NSArray *copyArray = [array copy]; //
NSMutableArray *mCopyArray = [array mutableCopy];
查看内容,可以看到 copyArray 和 array 的地址是一样的,⽽ mCopyArray 和 array的地址是不同的。说明 copy 操作进⾏了指针拷贝,mutableCopy 进⾏了内容拷贝。但需要强调的是:此处的内容拷贝,仅仅是拷贝 array 这个对象,array 集合内部的元素仍然是指针拷贝。这和上面的非集合 immutable 对象的拷⻉还是挺相似的,那么mutable对象的拷贝会不会类似呢?我们继续往下,看 mutable 对象拷贝的例子:
NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableStringstringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];查看内存,如我们所料,copyArray、mCopyArray和 array 的内存地址都不一样,说明 copyArray、mCopyArray 都对 array 进⾏了内容拷贝。同样,我们可以得出结论:
在集合类对象中,对 immutable 对象进行 copy,是指针复制, mutableCopy 是内
容复制;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。但是:集合对
象的内容复制仅限于对象本身,对象元素仍然是指针复制。⽤代码简单表示如下:
[immutableObject copy] // 浅复制
[immutableObject mutableCopy] //单层深复制
[mutableObject copy] //单层深复制
[mutableObject mutableCopy] //单层深复制
这个代码结论和非集合类的非常相似。
举例:
// 测试深复制于浅复制
self.dataArr = [NSMutableArray array];
NSMutableString *str1 = [NSMutableString string];
[str1 appendFormat:@"a"];
[str1 appendFormat:@"b"];
NSLog(@"str1:%@",str1);
// self.string = str1; // string的属性用copy 改变str1的时候才不会影响string
[self.dataArr addObject:str1];
NSLog(@"dataArr:%@",_dataArr);
self.dataArrSuper = [NSArray arrayWithArray:self.dataArr]; // arrayWithArray 是深拷贝 dataArrSuper对dataArr进行深拷贝, 如果没有 self.string = str1(且self.string 的属性使用copy) 这一步 对于dataArr内部的str1还是浅拷贝
NSLog(@"dataArr:%p dataArrSuper:%p",self.dataArr,self.dataArrSuper);
NSLog(@"%p",str1);
NSLog(@"dataArr中的str1:%p dataArrSuper的str1:%p",self.dataArr[0],self.dataArrSuper[0]);
NSLog(@"dataArrSuper:%@",_dataArrSuper);
// 此下为对集合类对象的深复制与浅复制测试
[_dataArr addObject:@"c"]; // 这是对dataArr数组本身操作,不会影响dataArrSuper;
[str1appendFormat:@"d"]; // dataArr内部可变字符串改变, 会影响dataArrSuper
NSLog(@"后dataArr:%@",_dataArr);
NSLog(@"后dataArrSuper:%@",_dataArrSuper);
总结一下:
1.用@property声明的NSString(或NSArray,NSDictionary)推荐使用copy关键
字
2.非集合类:只有不可变对象进行copy操作时是浅复制([immutableObject copy] // 浅复制),其他都是深复制
3.集合类:只有不可变对象进行copy操作时是浅复制([immutableObject copy] // 浅复制),其他都是单层深复制(参考本文最上方单层深复制解释)
俗话说:“好记性不如烂笔头”,如果咬文嚼字认真看了一遍还是觉得模棱两可的话,建议亲自敲一小段代码尝试一下,查看一下其内容的变化,会对你印象更深刻。
如果有什么问题,欢迎大家批评指正,我们一同走上溜光大道!!!
你拼命赚钱的样子虽然有些狼狈,但是你靠自己的样子真的很美!加油