iOS进阶之深拷贝和浅拷贝

2019-08-20  本文已影响0人  枫叶无处漂泊

前言

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

概念

深拷贝和浅拷贝的示意图.png

copy和mutablecopy概念

非集合类对象的copy与mutableCopy

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

NSString *string = @"origin";
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];

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

再看mutable对象拷贝例子:

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 四个对象的内存地址都不一样,说明此时都是做内容拷贝.

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

集合类对象的copy与mutableCopy

<__NSArrayM 0x600001963540>(
a,
b,
c
)

(lldb) po copyArray

<__NSArrayI 0x6000019635d0>(
a,
b,
c
)

(lldb) po mCopyArray

<__NSArrayM 0x600001963390>(
a,
b,
c,
d
)

(lldb) po m1CopyArray

<__NSArrayI 0x600001963570>(
a,
b,
c
)

```
打印的地址可以得出结论:

* 在集合类对象中,对immutable对象进行copy,是指针复制,mutableCopy是内容复制。
*  在集合类对象中,对mutable对象进行copy和mutableCopy都是内容复制。
* 在集合类对象中,对对象进行copy的对象就是不可变的,进行mutable就是可变的

为啥对NSString、NSArray、NSDictionary进行copy,如果进行strong处理有什么后果

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

//定义一个以 strong 修饰的 array:
@property (nonatomic ,readwrite, strong) NSArray *array;

进行如下操作

   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);
   

打印结果如下所示:

self.array:(
),
self.array:(
   1,
   2,
   3,
   4
)

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

总结

通过本章了解,可以大概总结一下几点:

上一篇 下一篇

猜你喜欢

热点阅读