iOS中的浅复制与深复制

当谈到对象复制时都绕不开浅复制与深复制的区分,它们是什么意思呢?

  • 浅复制:只复制对象的指针,两个对象指向的还是同一个地址的内容,操作一个时会影响另一个的值。
  • 深复制:复制对象的内容,两个对象指向两个不同地址的内容,操作一个时不会影响另一个的值。

在OC中,因为采用内存计数的方式管理内存,所以浅复制时会对同一个内容计数加一,深复制则不会。

在OC中,复制操作有copy和mutableCopy两种方法,那哪种是浅复制哪种是深复制呢?

非集合对象

先把对象大致分为两类:非集合对象与集合对象,至于为什么要这么分,待会讲集合对象的时候再说。

非集合对象就是指NSString、NSNumber等本身就是具体内容的对象。像NSString这种对象,还有一个相关的叫NSMutableString。所以在非集合对象中又可以分为可变对象和不可变对象。

对他们进行copy与mutableCopy的含义是:

  • 对于不可变非集合对象(如NSString),copy操作是浅复制,只会复制指针,mutableCopy操作是深复制,
  • 对于可变非集合对象(如NSMutableString),copy和mutableCopy都是深复制,都会创建一个新的同样的内容来返回,但是要注意,copy返回的是不可变对象,也就是说即使你对一个NSMutableString做copy操作,返回给另一个NSMutableString,然后去对这个NSMutableString做变化操作,会报错。

用代码来看如下:

NSString *string = @"origin";
NSString *stringCopy = [string copy];// 浅复制
NSMutableString *stringMCopy = [string mutableCopy];// 深复制

NSMutableString *string = [NSMutableString stringWithString: @"origin"];
NSString *stringCopy = [string copy];// 深复制
NSMutableString *mStringCopy = [string copy];// 深复制
NSMutableString *stringMCopy = [string mutableCopy];// 深复制
[mStringCopy appendString:@"mm"]; // crash

集合对象

上面说了非集合对象,那什么是集合对象呢?集合对象就是指NSArray、NSDictionary、NSSet这些包含其他对象的对象。

为什么要做这个区分呢?因为浅复制、深复制这两个概念其实并不完全,更准确的应该分为三种:浅复制、深复制、完全深复制。

在OC中,当你对一个集合对象做深复制时,这个深复制只是单层的,集合内的元素对象其实还只是引用,并不是每一层都是深复制,这一情况,苹果定义为单层深复制(one-level-deep copy)。只有对集合内的每一层都去做深复制,才能够称为完全深复制。

先说说简单的浅复制与深复制,其实与非集合对象差不多:

  • 对于不可变集合对象(如NSArray),copy操作是浅复制,只会复制指针,mutableCopy操作是深复制,
  • 对于可变集合对象(如NSMutableArray),copy和mutableCopy都是深复制,都会创建一个新的同样的内容来返回,但是要注意两点,一是copy返回的还是不可变对象,二就是上面说的,这个深复制只是单层深复制,里面包含的元素还是指针浅复制。

代码来说就是:

NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"];
NSArray *copyArray = [array copy];// 浅复制
NSMutableArray *mCopyArray = [array mutableCopy];// 单层深复制

NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArray = [array copy];// 单层深复制,返回不可变对象
NSMutableArray *mCopyArray = [array mutableCopy];// 单层深复制

那如果要做完全深复制该怎么做呢?

有两种方法:

  • 一种是用如下所示的方法:
NSDictionary shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];

copyItems设为YES会对集合中的每一个对象尝试做深复制,但是要求集合中的元素对象遵循NSCopying 协议,否则就会报错。但这其实还是对元素这一层的单层深复制,再下去也没有完全深复制。

  • 另一种方法是对集合做归档和解档(关于归档与解档可以看传送门:iOS存储方式之归档):
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];

以上就是OC中浅复制与深复制的各种应用了,要自己测试到底操作是浅复制还是深复制,可以通过看对象的引用计数是否增加:

NSLog(@"mArray retain count: %d", [mArray retainCount]);// ARC下不可用

或者直接看两个对象的地址是否一致:

NSLog(@"string自身指针的地址:%x", &str);
NSLog(@"string指针指向的对象的地址:%p", str);

版权所有:http://blog.csdn.net/cloudox_

你可能感兴趣的:(iOS,拾遗iOS之海)