iOS 深拷贝和浅拷贝的概念
浅拷贝(Shallow copy):是指针复制,它们指向共同的内存地址,没有开辟新的空间。相当于对象做一次retain操作,引用计数加1。
深拷贝(Deep copy):是指内容拷贝,拷贝后的对象会分配新的内存空间,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。源对象的引用计数不变,副本对象的引用计数为1。
浅拷贝就是指针拷贝,深拷贝就是内容拷贝;质区别在于是否开启新的内存空间、是否影响内存地址的引用计数。
深浅拷贝的概念我们明白了,那么思考几个问题
1、以NSArray、NSMutableArray举例,分别进行copy和mutableCopy是深拷贝还是浅拷贝
2、NSArray用copy还是strong修饰,NSMutableArray呢
3、如果一个数组里的数据是model类型的,对数组进行深拷贝以后,model是深拷贝还是浅拷贝
1、对NSArray、NSMutableArray分别进行copy和mutableCopy
得出结论,只有NSArray进行copy操作,是浅拷贝,其他都是深拷贝,也很好理解,只有不可变数组copy成不可变可以共用一个数组,其他都是有可变数组的情况,自然不希望一个数组改变影响了另外一个数组。
2、NSArray我们通常用copy修饰,NSMutableArray用strong修饰,为什么呢,看以下代码
打印值是什么呢?
答案是copyArr=@[@"1"] strongArr=@[@"1",@"2"],因为cArr使用copy修饰的,所以赋值时会copy进行一个深拷贝,形成两个不同的数组,所以对oldMutableArr操作时不影响cArr,我们定义不可变数组一般是希望它数组内容不可变,所以一般用copy来进行修饰。
而可变数组,在执行[self.cMutableArr addObject:@"3"];时会崩溃,
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x600000984920'
理由是一样的,就是使用copy修饰,赋值时进行copy操作,所以虽然cMutableArr定义时是NSMutableArray,但copy修饰,赋值以后是个不可变数组,对不可变数组进行添加操作,就崩溃了。
3、对一个model类型数组进行深拷贝,里面的model也会深拷贝吗?
答案是并不会,对model类型数组进行深拷贝只会形成两个数组,但是里面的model是还是指向之前的指针,但是我们有时候会有这样的业务需求,想要两个数组完全独立,那么如何能实现model也深拷贝呢?
第一种方法是苹果提供的一个api,initWithArray:copyItems: with YES
NSArray *newArr = [[NSArray alloc] initWithArray:oldArr copyItems:YES];
这样model也会进行一个copy,要注意的是,用这个方法进行拷贝,数组里面的模型就要实现copyWithZone:/mutableCopyWithZone方法;如果不实现的话,就会报运行时错误。
这里顺便提一下copyWithZone的一个注意点,如果有Person,Student两个类,后者是前者的子类,都需要实现NSCopying。
按照上面代码写的时候,对Student类型对象copy时会崩溃,因为[super copyWithZone:zone];这个方法返回的是个Person类型的,所以s.number会报找不到number方法。所以在实现copyWithZone的时候最好写成
Person *p = [[[self class] allocWithZone:zone] init];
但是initWithArray:copyItems: with YES 这种方法,如果模型属性还包含模型,就需要在方法里对包含的模型进行copy。
但是这样写如果模型比较复杂,这里介绍第二种方法,用归档解档
NSArray* newArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];。
使用归档和解档需要模型遵守NSCoding协议并重写initWithCoder和encodeWithCoder
备注:如果模型中有嵌套子模型,子模型也需要实现上述方法,否则会报运行时错误。
二者都可以对模型进行深拷贝,但是initWithArray:copyItems适用于对一级模型进行深拷贝,模型较复杂时,归档和解档更简洁。
网友评论