美文网首页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 深浅拷贝的那些事

    iOS 深拷贝和浅拷贝的概念 浅拷贝(Shallow copy):是指针复制,它们指向共同的内存地址,没有开辟新的...

  • iOS 深浅拷贝

    iOS深浅拷贝

  • 关于深浅拷贝的那些事

    前言 所谓深浅拷贝,其实都是进行复制,主要区别在于复制出来的新对象和原来的对象时候会相互影响。深浅拷贝的区分:B ...

  • iOS深浅拷贝

    授权转载,作者:西木柚子 OC对象的三种拷贝方式 OC的对象拷贝有如下三种方式,很多时候我们把深复制和完全复制混为...

  • iOS深浅拷贝

    简述深浅拷贝 我们实例化的对象存储在堆区,而指向对象的指针一般存储在栈区。我们需要知道这个前提。  实际上拷贝分为...

  • iOS深浅拷贝

    浅拷贝:复制一个指针,仍然指向已经存在的内存深拷贝:复制一个指针,并新申请一个内存 关于拷贝的引用计数:浅拷贝:a...

  • iOS 深浅拷贝

    一、引言 我们都知道,iOS中的对象,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutable...

  • iOS 深浅拷贝

    http://www.cocoachina.com/cms/wap.php?action=article&id=2...

  • iOS深浅拷贝

    (本文根据CocoaChina上的一篇帖子整理,后期附上链接)最开始,我们需要清楚一些关于内存分配方式的基础知识。...

  • iOS深浅拷贝

    引言 在对于自定义的对象支持copy功能,也就是我们要给自定义的对象发送copy message,那我们就要手动实...

网友评论

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

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