首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >iOS 进阶之深拷贝和浅拷贝

iOS 进阶之深拷贝和浅拷贝

作者头像
网罗开发
发布2021-01-29 15:01:32
发布2021-01-29 15:01:32
1.6K0
举报
文章被收录于专栏:网罗开发网罗开发

目录

1. 前言

2. 概念

3. copy 和 mutablecopy

4. 非集合类对象的 copy 与 mutableCopy

5. 集合类对象的 copy 与 mutableCopy

6. copy 与 strong 对比

7. 总结

1. 前言

在开发的时候,使用copy的频率还是挺高的,我们只要copy定义的属性的设置方法并不保留新值,只是其拷贝一份值,为什么NSString、NSArray、NSDictionary属性的定义说那个copy,如果使用strong关键字有什么问题?所以这节就讲一下以及什么使用深拷贝和浅拷贝的问题。

2. 概念

  • 浅拷贝:浅拷贝就是指针拷贝,就是拷贝一份指向该对象的指针,就是复制的对象和原对象都指向同一个地址
  • 深拷贝:深拷贝是内容拷贝,真正的复制一份,复制对象的内容。复制的对象指向新的地址。如下图:

3. copy 和 mutablecopy

  • copy:copy拷贝出来的对象类型总是不可变类型(例如, NSString, NSDictionary, NSArray等等)
  • mutableCopy拷贝出来的对象类型总是可变类型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
  • 对象要想具有copy和mutablecopy功能要是NSCopying和NSMutableCopy协议,实现copywithzone和mutablecopywithzone

4. 非集合类对象的copy与mutableCopy

系统非集合类对象指的是 NSString, NSNumber ... 之类的对象。下面先看个非集合类immutable对象拷贝的例子

代码语言:javascript
复制
NSString *string = @"origin";
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];

通过查看内存,可以看到 stringCopy 和 string 的地址是一样,进行了指针拷贝;而 stringMCopy 的地址和 string 不一样,进行了内容拷贝;

再看mutable对象拷贝例子:

代码语言:javascript
复制
NSMutableString *string = [NSMutableString stringWithString: @"origin"];
//copy
NSString *stringCopy = [string copy];
NSMutableString *mStringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
//change value
[mStringCopy appendString:@"mm"]; //crash
[string appendString:@" origion!"];
[stringMCopy appendString:@"!!"];

运行以上代码,会在第7行crash,原因就是 copy 返回的对象是 immutable 对象。注释第7行后再运行,查看内存,发现 string、stringCopy、mStringCopy、stringMCopy 四个对象的内存地址都不一样,说明此时都是做内容拷贝。

在非集合类对象中得出结论:

  • 对immutable对象进行copy操作,是指针复制mutableCopy操作时内容复制
  • 对mutable对象进行copy和mutableCopy都是内容复制
  • 可变对象通过copy之后就变成不可变了对象

5. 集合类对象的copy与mutableCopy

5.1 对不可变集合类:

不可变集合类对象是指NSArray、NSDictionary、NSSet ... 之类的对象。下面先看集合类immutable对象使用copy和mutableCopy的一个例子:

代码语言:javascript
复制
NSArray *array = @[@[@"a", @"b"],   @[@"c", @"d"];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array     mutableCopy];
[mCopyArray addobject: @"e"];

查看内容,可以看到copyArray和array的地址是一样的,而mCopyArray和array的地址是不同的。说明copy操作进行了指针拷贝,mutableCopy进行了内容拷贝。mCopyArray可以添加对象,是可变对象。

强调:此处的内容拷贝,仅仅是拷贝array这个对象,array集合内部的元素仍然是指针拷贝。

5.2 对可变集合类:

可变集合类对象是指NSMutableArray、NSMutableDictionary、NSMutableSet ... 之类的对象。下面先看集合类immutable对象使用copy和mutableCopy的一个例子

代码语言:javascript
复制
NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArray = [array copy];
NSMutableArray *m1CopyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];
[mCopyArray addObject:@"d"];
[m1CopyArray addObject:@"d"]; //crash

查看内存,

代码语言:javascript
复制
(lldb) po array
<__NSArrayM 0x600001963540>(
a,
b,
c
)
代码语言:javascript
复制
(lldb) po copyArray
<__NSArrayI 0x6000019635d0>(
a,
b,
c
)
代码语言:javascript
复制
(lldb) po mCopyArray
<__NSArrayM 0x600001963390>(
a,
b,
c,
d
)
代码语言:javascript
复制
(lldb) po m1CopyArray
<__NSArrayI 0x600001963570>(
a,
b,
c
)
代码语言:javascript
复制
打印的地址可以得出结论:
在集合类对象中,对immutable对象进行copy,是指针复制,mutableCopy是内容复制。在集合类对象中,对mutable对象进行copy和mutableCopy都是内容复制。在集合类对象中,对对象进行copy的对象就是不可变的,进行mutable就是可变的

6. copy 与 strong 对比

copy 此特质所表达的所属关系与 strong 类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。当属性类型为 NSString 时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个 NSMutableString 类的实例。这个类是 NSString 的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。例如:

代码语言:javascript
复制
//定义一个以 strong 修饰的 array:
@property (nonatomic ,readwrite, strong) NSArray *array;

进行如下操作

代码语言:javascript
复制
   NSArray *array = @[ @1, @2, @3, @4 ];
   NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];

   self.array = mutableArray;
   [mutableArray removeAllObjects];;
   NSLog(@"self.array:%@",self.array);

   [mutableArray addObjectsFromArray:array];
   self.array = [mutableArray copy];
   [mutableArray removeAllObjects];;
   NSLog(@"self.array:%@",self.array);

打印结果如下所示:

代码语言:javascript
复制
self.array:(
),
self.array:(
   1,
   2,
   3,
   4
)

结果说明如果使用strong来定义不可变对象,它的子类可变对象,有可能该对象的指针指向他的子类,他的子类改变了,该对象也就改变了。这样就不经意篡改了该对象的值,不安全了。

7. 总结

通过本文,可以大概总结一下几点:

  • 对于不可变对象(不可变对象和不可变集合对象),进行copy都是指针拷贝,进行mutablecopy都是内容拷贝。
  • 对于可变对象(可变对象和可变集合对象),进行copy和mutablecopy都是内容copy。
  • 不管是可变对象和不可变对象进行copy操作,产生的都是不可变的对象,进行mutablecopy操作产生的都是可变的对象。
  • 对任何一个对象进行深拷贝,都是单层深拷贝。例如:对NSArray进行深拷贝,但是数组里面的元素还是指针拷贝。就是两个数组的地址不一样,但是里面的元素地址是一样的。所以要想让数组中的元素也是不一样的地址,那就对每个元素进行深拷贝。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网罗开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3. copy 和 mutablecopy
  • 4. 非集合类对象的 copy 与 mutableCopy
  • 5. 集合类对象的 copy 与 mutableCopy
  • 6. copy 与 strong 对比
  • 7. 总结
  • 1. 前言
  • 2. 概念
  • 3. copy 和 mutablecopy
  • 4. 非集合类对象的copy与mutableCopy
  • 5. 集合类对象的copy与mutableCopy
  • 6. copy 与 strong 对比
  • 7. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档