今天学习了一下iOS中关于深拷贝和浅拷贝的一些概念,感觉是真的绕,把我虎的一愣一愣的,更加加深了我对自己没有好好学习OC基础的鄙视,悲剧啊!言归正传,在一天的学习下来以后,总算对深拷贝和浅拷贝有了一些理解,这里就赶紧写下来加深印象。
1:copy 和 mutablecopy
- copy拷贝出来的对象类型总是不可变类型(例如, NSString, NSDictionary, NSArray等等)
- mutableCopy拷贝出来的对象类型总是可变类型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
下面用例子来简单解释一下
NSString *str1 = @"我是字符串";
NSString *str2 = [str1 copy];
NSMutableString *str3 = [str1 mutableCopy];
NSString *str4 = [str1 mutableCopy];
(lldb) p str1
(__NSCFConstantString *) $1 = 0x0000000105981060 @"我是字符串"
(lldb) p str2
(__NSCFConstantString *) $2 = 0x0000000105981060 @"我是字符串"
(lldb) p str3
(__NSCFString *) $3 = 0x000060000007edc0 @"我是字符串"
(lldb) p str4
(__NSCFString *) $4 = 0x000060000007ef40 @"我是字符串"
这里需要解释一下,在runtime下NSString
的“真身”是__NSCFConstantString
而NSMutableString
的“真身”是__NSCFString
,然后我们就能很清楚的看到,只要是copy得到的值就是不可变类型,而mutablecopy得到的是可变类型。
2:深拷贝和浅拷贝
用一张图来介绍一下:
这里先描述一下两个概念,一个是immutableObject
【不可变对象如:NSString
,NSArray
等】,另一个是mutableObject
【可变对象例如:NSMutableString
,NSMutableArray
等】;
在非集合类对象中:
对 immutable 对象进行 copy 操作,是指针复制【浅拷贝】,mutableCopy 操作时内容复制【深拷贝】;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。用代码简单表示如下:
- [immutableObject copy] // 浅复制
- [immutableObject mutableCopy] //深复制
- [mutableObject copy] //深复制
- [mutableObject mutableCopy] //深复制
下面用例子展示一下:
NSString *str1 = @"我是字符串";
NSString *str2 = [str1 copy];
NSMutableString *str3 = [str1 mutableCopy];
NSMutableString *mutableStr1 = [NSMutableString stringWithString:@"我也是字符串"];
NSString *mutableStr2 = [mutableStr1 copy];
NSMutableString *mutableStr3 = [mutableStr1 mutableCopy];
然后用debug模式下,把这两个字符串p出来
(lldb) p str1
(__NSCFConstantString *) $0 = 0x000000010d5c6060 @"我是字符串"
(lldb) p str2
(__NSCFConstantString *) $1 = 0x000000010d5c6060 @"我是字符串"
(lldb) p str3
(__NSCFString *) $2 = 0x000061800026c340 @"我是字符串"
(lldb) p mutableStr1
(__NSCFString *) $3 = 0x000061800026c4c0 @"我也是字符串"
(lldb) p mutableStr2
(__NSCFString *) $4 = 0x00006180000555a0 @"我也是字符串"
(lldb) p mutableStr3
(__NSCFString *) $5 = 0x000061800026c100 @"我也是字符串"
可以看出,除了对immutable的Copy动作得到的string是浅拷贝外,其他的都是深拷贝。
在集合类对象中:
对 immutable 对象进行 copy,是指针复制【浅拷贝】, mutableCopy 是内容复制【深拷贝】;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。但是:集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制。用代码简单表示如下:
- [immutableObject copy] // 浅复制
- [immutableObject mutableCopy] //单层深复制
- [mutableObject copy] //单层深复制
- [mutableObject mutableCopy] //单层深复制
这里说的单层深复制其实就是所谓的不完全深拷贝,这个跟Java中的深拷贝概念又有所区别,iOS中集合对象的“深拷贝”只拷贝了一个壳,对于壳内的元素是浅拷贝,和java中递归的深拷贝有所不同。
3:property中的copy属性
了解完上面说的copy和mutablecopy,就可以讲讲property中的copy属性了。简单的用几行代码来表示copy属性的意思的话,就是下面这样:
@property (copy, nonatomic) NSString *someString;
- (void)setSomeString:(NSString *)someString
{
//没有写copy属性时
_someString = someString;
//写了copy属性时
_someString = [someString copy];
}
下面是摘自《招聘一个靠谱的 iOS》
- 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
- 如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
也就是说,当你加上一个copy属性时,这个对象在被set的时,就不再是改变这个对象的原有内存,而是修改这个对象的不可变副本内存。这样就能够保证这个元素不会被外部修改影响
接下来用一个例子来解释一下:
@property (nonatomic ,strong) NSArray *array;
NSArray *array = @[ @1, @2, @3, @4 ];
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];
self.array = mutableArray;
[mutableArray removeAllObjects];
那么这个时候self.array的值到底是@[ @1, @2, @3, @4 ]还是一个空的的数组呢。下面是结果
(lldb) po self.array
<__NSArrayM 0x60800025a9d0>(
)
这就是property里不用copy而用strong的结果,当你确定这个元素是不可变的,那么copy属性还是很有必要的,不然在接下的代码中,你什么时候不小心把他改了你都不知道(╯‵□′)╯︵┻━┻