写在前面

关于copymutableCopystrong,一直想好好整理整理,但是因为各种原因搁置了。今天上班时发现老代码中因为这个问题出现了一个特别恶心的大坑,让我下定决心写下这篇博文。如果你认为自己没掌握copy相关知识,建议看看此文,这里会有你需要的;如果你认为自己掌握了copy相关知识,也建议看看此文,也许这里有你感兴趣的东西。

首先和大家回顾一下有关copy的两个概念——浅拷贝(Shallow Copy)深拷贝(Deep Copy)

浅拷贝:只拷贝指针,不拷贝内容(不用为内容分配新的内存空间);
深拷贝:同时拷贝指针和内容,即分配一块新的内存,将原内容复制一份到该内存中,并生成指向该内存的新指针。(这里谢谢@灿烂天空的提醒,原来的解释可能不太准确,特此修正)
通俗点解释就是,已知一条路,通往罗马,浅拷贝就是新建一条通往这个罗马的路。而深拷贝则是选一个地方,按照原来的罗马新建一个(罗马内部包含的所有东西全部照旧的新建,比如家居、文化等等),并修一条通往新罗马的路,这样原来罗马怎么样就跟新罗马没关系了。

In the case of collection objects, a shallow copy means that a new collection object is created, but the contents of the original collection are not duplicated—only the object references are copied to the new container.

A deep copy duplicates the compound object as well as the contents of all of its contained objects.

四种copy情况

不可变非集合类对象的copy

直接上代码:

NSString *immutableStr = @"KFA_test1";
NSString *copyImmutableStr = [immutableStr copy];
NSString *mutableCopyImmutableStr = [immutableStr mutableCopy];
NSLog(@"\\nimmutableStr:%p-%p\\ncopyImmutableStr:%p-%p\\nmutableImmutableStr:%p-%p",immutableStr,&immutableStr,copyImmutableStr,&copyImmutableStr,mutableCopyImmutableStr,&mutableCopyImmutableStr);
复制代码

运行结果

immutableStr:0x103426098-0x7fff5c7dba08
copyImmutableStr:0x103426098-0x7fff5c7dba00
mutableImmutableStr:0x7ffd99d34ce0-0x7fff5c7db9f8
复制代码

可以发现,对不可变非集合类对象进行copy时,只拷贝了指针,内容不拷贝。对不可变非集合类对象进行mutableCopy时,同时拷贝了指针和内容。

可变非集合类对象的copy

照例上代码:

NSMutableString *mutableStr = [@"KFA_test2" mutableCopy];
NSString *copyImmutableStr = [mutableStr copy];
NSString *mutableCopyImmutableStr = [mutableStr mutableCopy];
NSLog(@"\\nmutableStr:%p-%p\\ncopyImmutableStr:%p-%p\\nmutableImmutableStr:%p-%p",mutableStr,&mutableStr,copyImmutableStr,&copyImmutableStr,mutableCopyImmutableStr,&mutableCopyImmutableStr);
复制代码

运行结果:

mutableStr:0x7feb8bc1c940-0x7fff5610fa08
copyImmutableStr:0xa34cf2e0400c1289-0x7fff5610fa00
mutableImmutableStr:0x7feb8bc1f320-0x7fff5610f9f8
复制代码

从结果可以发现,对可变非集合类对象进行copymutableCopy,都同时拷贝指针和内容。

不可变集合类对象的copy

这里以数组为例:

NSArray *immutableArr = @[@"KFA_test3"];
NSString *immu = immutableArr.firstObject;
NSArray *copyImmutableArr = [immutableArr copy];
NSString *copyImmu = copyImmutableArr.firstObject;
NSArray *mutableCopyImmutableArr = [immutableArr mutableCopy];
NSString *mutableCopyImu = mutableCopyImmutableArr.firstObject;
NSLog(@"\\nimmutableArr:%p-%p\\ncopyImmutableArr:%p-%p\\nmutableCopyImmutableArr:%p-%p\\nimmu:%p-%p\\ncopyImmu:%p-%p\\nmutableCopyImu:%p-%p",immutableArr,&immutableArr,copyImmutableArr,&copyImmutableArr,mutableCopyImmutableArr,&mutableCopyImmutableArr,immu,&immu,copyImmu,&copyImmu,mutableCopyImu,&mutableCopyImu);
复制代码

运行结果:

immutableArr:0x7fa44a7087d0-0x7fff576619d0
copyImmutableArr:0x7fa44a7087d0-0x7fff576619c0
mutableCopyImmutableArr:0x7fa44a703370-0x7fff576619b0
immu:0x1085a0118-0x7fff576619c8
copyImmu:0x1085a0118-0x7fff576619b8
mutableCopyImu:0x1085a0118-0x7fff576619a8
复制代码

不难发现,对不可变集合类对象进行copy时,只拷贝指针,不拷贝内容。对不可变集合类对象进行mutableCopy时,同时拷贝指针和内容,但是这里的内容只针对集合对象本身,对于集合内的元素只拷贝指针,不拷贝内容。

可变集合类对象的copy

还是以数组为例:

NSArray *mutableArr = [@[@"KFA_test3"] mutableCopy];
NSString *mu = mutableArr.firstObject;
NSArray *copyImmutableArr = [mutableArr copy];
NSString *copyImmu = copyImmutableArr.firstObject;
NSArray *mutableCopyImmutableArr = [mutableArr mutableCopy];
NSString *mutableCopyImu = mutableCopyImmutableArr.firstObject;
NSLog(@"\\nmutableArr:%p-%p\\ncopyImmutableArr:%p-%p\\nmutableCopyImmutableArr:%p-%p\\nmu:%p-%p\\ncopyImmu:%p-%p\\nmutableCopyImu:%p-%p",mutableArr,&mutableArr,copyImmutableArr,&copyImmutableArr,mutableCopyImmutableArr,&mutableCopyImmutableArr,mu,&mu,copyImmu,&copyImmu,mutableCopyImu,&mutableCopyImu);
复制代码

运行结果:

mutableArr:0x7feacbd0d250-0x7fff521409d0
copyImmutableArr:0x7feacbd06ef0-0x7fff521409c0
mutableCopyImmutableArr:0x7feacbd0c2a0-0x7fff521409b0
mu:0x10dac1118-0x7fff521409c8
copyImmu:0x10dac1118-0x7fff521409b8
mutableCopyImu:0x10dac1118-0x7fff521409a8
复制代码

我们发现,对可变集合类对象进行copymutableCopy时,都同时拷贝指针和内容。这里的内容跟上文一样只针对集合对象本身,对于集合内部的元素只拷贝指针,不拷贝内容。

strong和copy

strong和copy下的字符串

先添加两个字符串ivar,分别用strong和copy修饰:

@property (nonatomic, strong) NSString *testStrongStr;
@property (nonatomic, copy) NSString *testCopyStr;
复制代码

然后写个测试方法:

- (void)testCopyAndStrongForString {NSString *immutableStr = @"KFA_test4";self.testStrongStr = immutableStr;self.testCopyStr = immutableStr;NSLog(@"\\nimmutableStr:%@\\nself.testStrongStr:%@\\nself.testCopyStr:%@",immutableStr,self.testStrongStr,self.testCopyStr);immutableStr = @"KFA_test4_change";NSLog(@"\\nimmutableStr:%@\\nself.testStrongStr:%@\\nself.testCopyStr:%@",immutableStr,self.testStrongStr,self.testCopyStr);NSMutableString *mutableStr = [@"KFA_test5" mutableCopy];self.testStrongStr = mutableStr;self.testCopyStr = mutableStr;NSLog(@"\\nmutableStr:%@\\nself.testStrongStr:%@\\nself.testCopyStr:%@",mutableStr,self.testStrongStr,self.testCopyStr);[mutableStr appendString:@"_change"];NSLog(@"\\nmutableStr:%@\\nself.testStrongStr:%@\\nself.testCopyStr:%@",mutableStr,self.testStrongStr,self.testCopyStr);
}
复制代码

运行结果:

immutableStr:KFA_test4
self.testStrongStr:KFA_test4
self.testCopyStr:KFA_test4
immutableStr:KFA_test4_change
self.testStrongStr:KFA_test4
self.testCopyStr:KFA_test4
mutableStr:KFA_test5
self.testStrongStr:KFA_test5
self.testCopyStr:KFA_test5
mutableStr:KFA_test5_change
self.testStrongStr:KFA_test5_change
self.testCopyStr:KFA_test5
复制代码

从结果可以看出,当赋值对象是不可变的字符串时,strongcopy的效果一样,因为当赋值对象为不可变的字符串时,copy修饰的ivar进行拷贝相当于上文中的对不可变对象进行copy,只拷贝指针,不考虑内容。但是当赋值对象为可变的字符串时,当赋值对象发生变化时,strong修饰的ivar会跟着变,copy修饰的ivar进行了拷贝(参考上文中对可变对象进行copy),所以不会变。这里可能有同学会有疑惑,为什么明明KFA_test4变成了KFA_test4_change,内容变了,而self.testStrongStrself.testCopyStr的内容没变,这是因为KFA_test4变成KFA_test4_change只是因为immutableStr指针进行了重指向指向了KFA_test4_change,而内容KFA_test4属于常量,存在栈区,本身并没有变。所以在修饰字符串时为了数据的安全,建议用copy,而不用strong

strong和copy下的数组

同样,先添加两个数组ivar,分别用strongcopy修饰:

@property (nonatomic, strong) NSArray *testStrongArr;
@property (nonatomic, copy) NSArray *testCopyArr;
复制代码

另外再创建一个model类,有一个number属性:

@interface KFACopyModel : NSObject@property (nonatomic, copy) NSString *number;@end
复制代码

再写两个函数(等会测试方法里会用到),用来同时打印三个数组(里面的元素):

void KFALog(NSArray *array1, NSArray *array2, NSArray *array3) {NSString *string1 = KFANSStringFromArray(array1);NSString *string2 = KFANSStringFromArray(array2);NSString *string3 = KFANSStringFromArray(array3);NSLog(@"\\n\\%@\\n%@\\n%@",string1,string2,string3);
}NSString *KFANSStringFromArray(NSArray *array) {NSMutableString *string = nil;for (NSString *objc in array) {NSString *objcStr = nil;if ([objc isKindOfClass:[NSString class]]) {objcStr = (NSString *)objc;}else if ([objc isKindOfClass:[KFACopyModel class]]) {KFACopyModel *model = (KFACopyModel *)objc;objcStr = model.number;}if (string == nil) {string = [objcStr mutableCopy];}else {[string appendFormat:@"_%@",objcStr];}}return string;
}
复制代码

然后就是测试方法了:

- (void)testCopyAndStrongForArray {NSArray *immutableArr = @[@"KFA_test6"];self.testStrongArr = immutableArr;self.testCopyArr = immutableArr;KFALog(immutableArr,self.testStrongArr,self.testCopyArr);immutableArr = @[@"KFA_test6_change"];KFALog(immutableArr,self.testStrongArr,self.testCopyArr);NSMutableArray *mutableArr = [@[@"KFA_test7"] mutableCopy];self.testStrongArr = mutableArr;self.testCopyArr = mutableArr;KFALog(mutableArr, self.testStrongArr, self.testCopyArr);[mutableArr replaceObjectAtIndex:0 withObject:@"KFA_test7_change"];KFALog(mutableArr, self.testStrongArr, self.testCopyArr);KFACopyModel *model1 = [[KFACopyModel alloc] init];model1.number = @"13789892310";NSArray *immutableArr_ = @[model1];self.testStrongArr = immutableArr_;self.testCopyArr = immutableArr_;KFALog(immutableArr_, self.testStrongArr, self.testCopyArr);model1.number = @"137****2310";KFALog(immutableArr_, self.testStrongArr, self.testCopyArr);KFACopyModel *model2 = [[KFACopyModel alloc] init];model2.number = @"13982650942";NSArray *mutableArr_ = @[model2];self.testStrongArr = mutableArr_;self.testCopyArr = mutableArr_;KFALog(mutableArr_, self.testStrongArr, self.testCopyArr);model2.number = @"139****0942";KFALog(mutableArr_, self.testStrongArr, self.testCopyArr);
}
复制代码

运行结果:

KFA_test6
KFA_test6_change
KFA_test6
KFA_test6
KFA_test7
KFA_test7
KFA_test7
KFA_test7_change
KFA_test7_change
KFA_test7
13789892310
13789892310
13789892310
137****2310
137****2310
137****2310
13982650942
13982650942
13982650942
139****0942
139****0942
139****0942
复制代码

我们发现一个有意思的问题,当数组里元素为字符串时,结果跟咱们预料的一样的,但是当数组的元素为KFACopyModel对象时,结果跟咱们预料有点出入了。这里就得回到上文说的四种情况了。对集合类对象进行copymutableCopy时,即便拷贝内容,拷贝的也是集合对象本身,对于集合内的元素只拷贝了指针,不拷贝内容。所以当数组里的元素KFACopyModel对象的number属性发生变化时,拷贝的数组里元素也会跟着变化。

写在最后

通过上文我们可以总结两点:

  • 对于凡是具有可变子类的类,如NSString有子类NSMutableStringNSArray有子类NSMutableArray,都用copy进行修饰,不用strong。但是对可变类,如NSMutableArray,应该用strong,不用copy,不然就会造成明明定义一个可变数组却不能调用可变数组的方法的后果。
  • 给数组ivar赋值时,为了数组的安全,最好用一个临时的数组对象(此对象不会在其他地方用到),更不能用一个数组ivar来给另一个数组ivar赋值。

本文用的代码全在这里,可以点击下载。欢迎拍砖和转发。

strong、copy和mutableCopy详解相关推荐

  1. (118)System Verilog 父类与子类对象复制(copy函数)详解

    (118)System Verilog 父类与子类对象复制(copy函数)详解 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog 父类与 ...

  2. C++ copy()函数用法详解(深入了解,一文学会)

    C++ 算法 copy() 函数用于将容器 [first,last] 的所有元素从结果开始复制到不同的容器中. 本文介绍了copy.strcpy.strncpy.memcpy.copy_n.copy_ ...

  3. copy语法 postgre_PostgreSQL copy 命令教程详解

    报文介绍PostgreSQL copy 命令,通过示例展示把查询结果导出到csv文件,导入数据文件至postgresql. 1. copy命令介绍 copy命令用于在postgreSql表和标准文件系 ...

  4. [转]iOS5 ARC学习笔记:strong、weak等详解

    iOS5中加入了新知识,就是ARC,其实我并不是很喜欢它,因为习惯了自己管理内存.但是学习还是很有必要的. 在iOS开发过程中,属性的定义往往与retain, assign, copy有关,我想大家都 ...

  5. oracle em中查看jiob,HTML5 中的 b/strong、i/em 详解

    这篇文章主要聊一聊 HTML5 中的 和 ,以及 和 . 从页面显示效果来看,被 和 包围的文字将会被加粗,而被 和 包围的文字将以斜体的形式呈现.那大家可能就会疑惑了,既然效果一样,那为什么还要重复 ...

  6. 2020-09-18 python中copy()和deepcopy()详解

    首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制出来的新对象产生影响. -–而浅复制并不会产生一个独立的对 ...

  7. copy.copy()与copy.deepcopy()的详解

    copy.copy() 元组和列表调用这个方法效果也不一样. 元组的效果: a = [1,2,3] b = [4,5,6] c = (a,b) e = copy.copy(c) 可以看到:e和c是指向 ...

  8. python中copy()和deepcopy()详解

    参考文章 http://iaman.actor/blog/2016/04/17/copy-in-python **首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独 ...

  9. python中deepcopy函数_python中copy()和deepcopy()详解

    **首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制出来的新对象产生影响. -–而浅复制并不会产生一个独立 ...

最新文章

  1. darknet53网络结构及配置文件对比
  2. 复位 stm32_stm32学习笔记
  3. 在php中如何实现cookie即时生效,不用刷新就可以使用
  4. 《2017年IT优先级调查》:重点考虑云、网络、端点安全
  5. 数据结构(莫队算法):国家集训队2010 小Z的袜子
  6. python太阳花绘制
  7. 2021-09-30
  8. 深入源码理解.NET Core中Startup的注册及运行
  9. Spring MVC-集成(Integration)-集成LOG4J示例(转载实践)
  10. Python内置数据类型之list
  11. 【Pytorch神经网络实战案例】24 基于迁移学习识别多种鸟类(CUB-200数据集)
  12. 近百家公司高级运维的面试题汇总
  13. MySQL的INSERT ··· ON DUPLICATE KEY UPDATE使用的几种情况
  14. Date java 1614619219
  15. 每天进步一点点《ML - DBSCAN》
  16. Intellij IDEA-我常用的快捷键
  17. mac用navicat连接mysql_Mac OS下,使用Navicat连接MySQL出现的问题
  18. DNS污染攻击详细教程
  19. 【云笔记9】Layui前端框架
  20. FFmpeg 录制桌面、麦克风、摄像头

热门文章

  1. 谈一谈CMU导师和学生的互动方式
  2. Python配置OpenCV时报错:ImportError DLL load failed: %1 不是有效的 Win32 应用程序
  3. 简明python教程 --C++程序员的视角(五):面向对象的编程
  4. 随机重命名MP3文件
  5. 区块链100讲:据说,80%的人都搞不懂哈希算法
  6. xslt的简单使用[xml--html]
  7. Create Custom Instruments
  8. git 客户端查看不同分支的文件
  9. 独家专访 | 从跨国投行到开源社区,IBM Spark总工程师Nick Pentreath的传奇经历
  10. Nginx服务器之基础学习