博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Copy修饰的NSArray
阅读量:5796 次
发布时间:2019-06-18

本文共 3519 字,大约阅读时间需要 11 分钟。

深复制与浅复制

简单点理解,深复制,在内存中拷贝一份新的对象。 浅复制,没有拷贝新的对象,只是一个地址的引用。 在赋值过程中深复制操作,原对象的引用计数不会增加,浅复制引用计数会加一。

copy操作和mutableCopy操作

一个类遵循NSCopying,NSMutableCopying协议并且实现相对应的初始化方法后,这个类就具有对象拷贝的能力。如果你自定义类没有遵守协议直接调用copy/mutableCopy程序会奔溃。拷贝协议的具体使用我这里不做扩展感兴趣的可以自行Google一下。有一些刚接触iOS开发的同学认为copy操作就是浅复制,mutableCopy就是深复制,这是一个非常错误的理解。以下是我的一些总结:

  • 可变的集合对象 + copy 得到一个新的对象(新对象不可变)深复制
  • 可变的集合对象 + mutablecopy 得到一个新的对象(新对象可变)深复制
  • 不可变集合对象 + copy 没有得到新的对象(地址的引用)浅复制
  • 不可变集合对象 + mutablecopy 得到一个新的对象(新对象可变)深复制 OC中集合对象NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、NSSet、NSMutableSet等,另外NSString、NSMutableString也准守以上原则。实践出真理我们来看看代码中的效果:
NSString *str = @"abc";    NSMutableString *mStr = [NSMutableString stringWithString:str];    NSString *strCopy = [str copy];    NSString *strMutableCopy = [str mutableCopy];    NSString *mStrCopy = [mStr copy];    NSString *mStrMutableCopy = [mStr mutableCopy];        NSArray *arr = @[@"abc"];    NSMutableArray *mArr = [NSMutableArray arrayWithArray:arr];    NSArray *arrCopy = [arr copy];    NSArray *arrMutableCopy = [arr mutableCopy];    NSArray *mArrCopy = [mArr copy];    NSArray *mArrMutableCopy = [mArr mutableCopy];        NSDictionary *dic = @{@"1":@"abc"};    NSMutableDictionary *mDic = [NSMutableDictionary dictionaryWithDictionary:dic];    NSDictionary *dicCopy = [dic copy];    NSDictionary *dicMutableCopy = [dic mutableCopy];    NSDictionary *mDicCopy = [mDic copy];    NSDictionary *mDicMutableCopy = [mDic mutableCopy];    NSSet *set = [NSSet setWithObject:@"1"];    NSMutableSet *mSet = [NSMutableSet setWithSet:set];    NSDictionary *setCopy = [set copy];    NSDictionary *setMutableCopy = [set mutableCopy];    NSDictionary *mSetCopy = [mDic copy];    NSDictionary *mSetMutableCopy = [mDic mutableCopy];复制代码

我们选取NSArray、NSMutableArray来看一下copy和mutableCopy的结果

stong与copy修饰符

strong和copy都可以用来修饰对象类型属性,strong修饰的属性,在将一个对象赋值给这个属性的时候,对象不会进行内存的拷贝,直接进行地址的引用,对象的引用计数+1;copy修饰的属性,如果该属性是一个非集合类型,那么赋值操作的效果和strong是一样的,如果该属性是一个集合类型,我们在下面在详细的解读。

NSMutableArray属性请使用strong修饰符

数学里面一个证明方式叫做反证法,接下来我们自定义一个类,增加一个NSMutableArray属性,使用copy来修饰

#import 
@interface TestObject : NSObject@property (nonatomic, copy) NSMutableArray *mutableArr;@end#import "TestObject.h"@implementation TestObject- (instancetype)init{ self = [super init];// self.mutableArr = [NSMutableArray arrayWithObject:@"1"]; _mutableArr = [NSMutableArray arrayWithObject:@"1"]; [self.mutableArr addObject:@"2"];//这一步,如果使用点语法进行属性赋值,程序crash;如果直接使用成员变量方式赋值,代码没有问题 return self;}//一般情况编译器会自动给属性添加get/set方法- (void)setMutableArr:(NSMutableArray *)mutableArr{ _mutableArr = [mutableArr copy];}@end复制代码

执行下面代码

TestObject *testObject = [TestObject new];testObject.mutableArr = [NSMutableArray arrayWithObject:@"1"];[testObject.mutableArr addObject:@"2"];复制代码

程序crash,控制台提示错误 [__NSSingleObjectArrayI addObject:]: unrecognized selector sent to instance 0x1c0017730 这一步我们就证明了如果我们使用copy来修饰一个可变的数组属性,然后通过点语法的方式把一个可变的数组赋值给该属性,最后该属性指向的是一个拷贝得到的全新的不可变数组,这个时候我们可以在代码中调用arrayWithObject等改变数组的api(因为@property (nonatomic, copy) NSMutableArray *mutableArr 告诉编译器这是一个可变的数组),但是在运行时,这个属性指向的是一个不可变的数组,引发unrecognized selector sent to instance 错误,从而导致crash。

NSArray属性请使用copy修饰符

我们定义一个NSArray类型的属性,目的是为了在初始化或者赋值操作后,这个数组集合就不能够改变的(增加或者删除元素等)。如果我们使用strong去修饰NSArray属性,并且我们把一个可变的数组NSMutableArray对象赋值给了该属性(父类的指针可以指向子类对象),strong并不会在内存中拷贝新的对象,只是一个地址的引用,所以NSArray类型的属性实质上指向的是一个NSMutableArray,这个时候如果其他地方还有一个NSMutableArray指针变量指向这个NSMutableArray对象,并且通过这个变量改变了数组,也会造成NSArray类型属性的改变,因为它们指向是一个地址内存,也就是一个对象。这就违背了我们设计的初衷,同时可能引发一些业务逻辑问题。

尾语

以上内容有任何的疑问、错误,请各路大神指出,同时希望能够帮助到大家

转载地址:http://btbfx.baihongyu.com/

你可能感兴趣的文章
MetricsGraphics.js —— 时间序列可视化库
查看>>
《Python爬虫开发与项目实战》——2.2 HTTP标准
查看>>
docker 任意端口启动jenkins (CentOs7 Docker 17.03.1-ce)
查看>>
线程间共享数据无需竞争
查看>>
从航空母舰上起飞,是怎样一种体验----EDAS带你快速搞定分布式应用
查看>>
容器就像监狱,让我们来构造一个监狱吧!(含代码下载)
查看>>
《C专家编程》一1.7 编译限制
查看>>
[Google Guava] 2.1-不可变集合
查看>>
三种数据分析法提升电商运营
查看>>
哪个线程执行 CompletableFuture’s tasks 和 callbacks?
查看>>
《数据科学与大数据分析——数据的发现 分析 可视化与表示》一2.10 练习
查看>>
Oracle ASM 翻译系列第六弹:高级知识 如何映射asmlib管理的盘到它对应的设备名...
查看>>
多线程之volatile关键字
查看>>
如何判断webview是不是滑到底部
查看>>
Raptor实践2——控制结构
查看>>
Smartisan OS一步之自定义拖拽内容
查看>>
《JavaScript权威指南第六版》学习笔记-对象
查看>>
开发者论坛一周精粹(第四期):Windows系统 SMB/RDP远程命令执行漏洞
查看>>
Kafka 0.10 常用运维命令
查看>>
常见的浏览器端数据存储方案
查看>>