美文网首页iOS
iOS 深浅拷贝的那些事

iOS 深浅拷贝的那些事

作者: 码代码的鱼 | 来源:发表于2022-03-29 18:12 被阅读0次

    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适用于对一级模型进行深拷贝,模型较复杂时,归档和解档更简洁。

    相关文章

      网友评论

        本文标题:iOS 深浅拷贝的那些事

        本文链接:https://www.haomeiwen.com/subject/ujxyjrtx.html