对NSArray和NSMutableArray的深拷贝/浅拷贝的探究

栏目: IOS · 发布时间: 6年前

内容简介:下面两个问题,面试的时候应该经常会被问到。今年三月份面试的时候,被这两个问题搞得很迷茫,今天特地研究了一下。相信您看完我的这篇文章和我有一样疑惑的您,心里会有一个清晰的答案。

一、原起

下面两个问题,面试的时候应该经常会被问到。

  1. NSArrayNSMutableArray 进行 copymutableCopy 分别会得到什么样的数组?
  2. NSString 作为一个对象的属性时,我们应该使用 strong 还是 copy 来修饰呢?

今年三月份面试的时候,被这两个问题搞得很迷茫,今天特地研究了一下。

相信您看完我的这篇文章和我有一样疑惑的您,心里会有一个清晰的答案。

二、NSMutableArray的copy和mutableCopy操作进行探究

//1、对NSArray分别使用`copy` & `mutableCopy`进行内存地址的对比
    NSArray *orgArr = @[@"ningjianwen", @"kongjiangmei"];
    NSArray *copyArr = [orgArr copy];
    NSMutableArray *mcopyArr = [orgArr mutableCopy];
    [mcopyArr addObject:@"jiangxianjin"];
    
    NSLog(@"NSArray 地址对比结果打印:");
    
    NSLog(@"orgArr 地址: %p", orgArr);
    NSLog(@"copyArr 地址: %p", copyArr);
    NSLog(@"mcopyArr 地址: %p", mcopyArr);

打印结果如下:

2019-06-13 20:05:48.915949+0800 ArrayCopyAndMutableCopy[54942:3399095] NSArray 地址对比结果打印:

2019-06-13 20:05:48.916073+0800 ArrayCopyAndMutableCopy[54942:3399095] orgArr 地址: 0x600003716bc0

2019-06-13 20:05:48.916189+0800 ArrayCopyAndMutableCopy[54942:3399095] copyArr 地址: 0x600003716bc0

2019-06-13 20:05:48.916266+0800 ArrayCopyAndMutableCopy[54942:3399095] mcopyArr 地址: 0x600003951b90

结果分析:

从打印结果可以看出 orgArrcopyArr 内存地址是一致的,说明 copy 对NSArray进行的是浅拷贝。 mcopyArrorgArr 内存地址是不一致的,说明 mutableCopy 对NSArray进行的是深拷贝,且拷贝之后数组变成了一个可变数组。

三、NSArray的copy和mutableCopy操作进行探究

//2、对NSMutableArray分别使用`copy` & `mutableCopy`进行内存地址的对比
    NSMutableArray *orgMArr = [NSMutableArray arrayWithObjects:@"星辰", @"江河",nil];
    NSArray *copyMArr = [orgMArr copy];
    NSMutableArray *mcopyMArr = [orgMArr mutableCopy];
    [mcopyMArr addObject:@"日月"];
    
    NSLog(@"NSMutableArray 地址对比结果打印:");
    
    NSLog(@"orgMArr 地址: %p", orgMArr);
    NSLog(@"copyMArr 地址: %p", copyMArr);
    NSLog(@"mcopyMArr 地址: %p", mcopyMArr);

打印结果如下:

2019-06-13 20:05:48.916348+0800 ArrayCopyAndMutableCopy[54942:3399095] NSMutableArray 地址对比结果打印:

2019-06-13 20:05:48.916418+0800 ArrayCopyAndMutableCopy[54942:3399095] orgMArr 地址: 0x600003951e90

2019-06-13 20:05:48.916482+0800 ArrayCopyAndMutableCopy[54942:3399095] copyMArr 地址: 0x600003716ba0

2019-06-13 20:05:48.916546+0800 ArrayCopyAndMutableCopy[54942:3399095] mcopyMArr 地址: 0x600003951da0

结果分析:

从打印结果可以看出 copyMArrorgMArr 内存地址是不一致的,说明 copy 对NSMutableArray进行的是深拷贝,拷贝之后的新数组是一个不可变数组。

mcopyMArr与 orgMArr 内存地址是不一致的,说明 mutableCopy 对NSMutableArray进行的是深拷贝,且拷贝之后是一个新的可变数组。

四、NSString的strong和copy修饰的探究

4.1 对不可变字符串使用strong和copy修饰的探究

//1、对于不可变字符串探究
    NSString *orgStr = @"ning";
    self.firstName = orgStr;
    NSLog(@"first print: firstName = %@, orgStr = %@", self.firstName, orgStr);
    orgStr = @"kong";
    //update orgStr value, print self.firstName again
    NSLog(@"second print: firstName = %@, orgStr = %@", self.firstName,orgStr);
    
    NSString *orgSecondStr = @"jianwen";
    self.secondName = orgSecondStr;
    NSLog(@"first print: secondName = %@, orgSecondStr = %@", self.secondName, orgSecondStr);
    orgSecondStr = @"jiangmei";
    //update orgSecondStr value, print self.secondName again
    NSLog(@"second print: secondName = %@, orgSecondStr = %@", self.secondName, orgSecondStr);

打印结果如下:

2019-06-13 19:49:07.604338+0800 ArrayCopyAndMutableCopy[54809:3391476] first print: firstName = ning, orgStr = ning

2019-06-13 19:49:07.604479+0800 ArrayCopyAndMutableCopy[54809:3391476] second print: firstName = ning, orgStr = kong

2019-06-13 19:49:07.604575+0800 ArrayCopyAndMutableCopy[54809:3391476] first print: secondName = jianwen, orgSecondStr = jianwen

2019-06-13 19:49:07.604653+0800 ArrayCopyAndMutableCopy[54809:3391476] second print: secondName = jianwen, orgSecondStr = jiangmei

结果分析:

从打印结果可以看出,对于静态字符串,无论是使用 strong 还是 copy 修饰,字符串之间的修改的都是独立的,不会互相影响。

4.2对可变字符串使用strong和copy修饰的探究

//2、对于可变字符串的探究
    NSMutableString *orgMStr = [NSMutableString stringWithFormat:@"宁"];
    self.firstName = orgMStr;
    NSLog(@"使用 strong 修饰,第一次打印 self.firstName = %@",self.firstName);
    [orgMStr appendFormat:@"建文"];
    NSLog(@"使用 strong 修饰,第二次打印 self.firstName = %@",self.firstName);
    
    NSMutableString *orgMStr2 = [NSMutableString stringWithFormat:@"孔"];
    self.secondName = orgMStr2;
    NSLog(@"使用 copy 修饰,第一次打印 self.secondName = %@",self.secondName);
    [orgMStr appendFormat:@"jiangmei"];
    NSLog(@"使用 copy 修饰,第二次打印 self.secondName = %@",self.secondName);

打印结果如下:

2019-06-13 19:49:07.604758+0800 ArrayCopyAndMutableCopy[54809:3391476] 使用 strong 修饰,第一次打印 self.firstName = 宁

2019-06-13 19:49:07.604857+0800 ArrayCopyAndMutableCopy[54809:3391476] 使用 strong 修饰,第二次打印 self.firstName = 宁建文

2019-06-13 19:49:07.604953+0800 ArrayCopyAndMutableCopy[54809:3391476] 使用 copy 修饰,第一次打印 self.secondName = 孔

2019-06-13 19:49:07.605043+0800 ArrayCopyAndMutableCopy[54809:3391476] 使用 copy 修饰,第二次打印 self.secondName = 孔

结果分析:

从打印的结果可以看出 strong 修饰的self.firstName两次的打印值是不一样的,第二次打印值和orgMstr是一样的,对orgMstr的修改,竟然影响了self.firstName的值,产生了我们不想要的结果(意外值串改)。这在开发中会导致预想不到的bug,排查困难。

而使用 copy 修饰的self.secondName两次的打印值是一样的,就是说orgMStr和self.secondName的修改是独立的,不会互相影响,这才是开发真正需要的效果。

4.3 总结

当字符串作为属性我们应该根据实际情况合理的选择修饰符( strong 或者 copy )。

  1. 对于只是简单的字符串赋值的属性,我们使用 strongcopy 修饰,效果是一样的;
  2. 但是对于涉及到可变字符串的修改赋值的属性,我们一定要使用 copy 进行修饰,这样才能保证代码的封装性,否则会产生值被意外修改的bug。
  3. 对于不好区分的情况,为了保证代码的封装性,就全部使用copy进行修饰吧。

五、没有demo的文章不是好文章

该对比分析的 demo传送门


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Information

The Information

James Gleick / Vintage / 2012-3-6 / USD 16.95

James Gleick, the author of the best sellers Chaos and Genius, now brings us a work just as astonishing and masterly: a revelatory chronicle and meditation that shows how information has become th......一起来看看 《The Information》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具