在iOS中关于深拷贝和浅拷贝以及copy属性的理解

今天学习了一下iOS中关于深拷贝和浅拷贝的一些概念,感觉是真的绕,把我虎的一愣一愣的,更加加深了我对自己没有好好学习OC基础的鄙视,悲剧啊!言归正传,在一天的学习下来以后,总算对深拷贝和浅拷贝有了一些理解,这里就赶紧写下来加深印象。

1:copy 和 mutablecopy

  1. copy拷贝出来的对象类型总是不可变类型(例如, NSString, NSDictionary, NSArray等等)
  2. 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的“真身”是__NSCFConstantStringNSMutableString的“真身”是__NSCFString,然后我们就能很清楚的看到,只要是copy得到的值就是不可变类型,而mutablecopy得到的是可变类型。

2:深拷贝和浅拷贝

用一张图来介绍一下:

在iOS中关于深拷贝和浅拷贝以及copy属性的理解_第1张图片
深拷贝和浅拷贝.png

这里先描述一下两个概念,一个是immutableObject【不可变对象如:NSStringNSArray等】,另一个是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》

  1. 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
  2. 如果我们使用是 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属性还是很有必要的,不然在接下的代码中,你什么时候不小心把他改了你都不知道(╯‵□′)╯︵┻━┻

你可能感兴趣的:(在iOS中关于深拷贝和浅拷贝以及copy属性的理解)