iOS中的深复制与浅复制

utgy0944 9年前

很多语言中都有深复制浅复制的概念,如C++,ObjC等。简单来说,浅复制就是两个变量指向了同一块内存区域,深复制就是两个变量指向了不同的内存区域,但是两个内存区域里面的内容是一样的。

浅复制示意图:

深复制示意图:

iOS开发中,浅复制和深复制要更复杂一些,涉及到集合对象和非集合对象的copy与mutableCopy。

非集合对象:如NSString,NSInteger,NSNumber……

集合对象:如NSArray,NSDictionary,……

1:非集合对象的copy与mutableCopy。

非集合对象的copy与mutableCopy,只需要遵循以下规则即可:

(1)可变对象的copy和mutableCopy方法都是深复制

(2)不可变对象的copy方法是浅复制,mutableCopy方法是深复制

(3)copy方法返回的对象是不可变对象

下面通过代码来验证:

可变对象的copy与 mutableCopy方法:

void testMutable()  {      //可变对象的复制,copy和mutableCopy都是深拷贝      NSMutableString *str1 = [NSMutableString stringWithString:@"test"];      NSMutableString *str2 = [str1 copy];      //copy返回的是不可变对象,因此str2不能改变,会发生崩溃      //[str2 appendString:@"test"];      NSMutableString *str3 = [str1 mutableCopy];      [str3 appendString:@"test"];      NSLog(@"%@ %@ %@",str1,str2,str3);      NSLog(@"%p %p %p",str1,str2,str3);  }

执行结果:

可以看到,三个字符串的地址是不相同的,说明copy和 mutableCopy方法都是深复制。

不可变对象的copy与mutableCopy方法:

void testNoMutable()  {      NSString *str1 = @"test";      //直接copy是浅复制      NSMutableString *str2 = [str1 copy];      //copy返回的是不可变对象,str2不能被修改,因此会发生崩溃      //[str2 appendString:@"test"];      //mutableCopy是深复制      NSMutableString *str3 = [str1 mutableCopy];      [str3 appendString:@"test"];      NSLog(@"%@ %@ %@",str1,str2,str3);      NSLog(@"%p %p %p",str1,str2,str3);  }

执行结果:

可以看到:前两个地址一样,第三个地址不一样,因此不可变对象的copy方法是浅复制,mutableCopy方法是深复制。

另外需要注意: 无论是可变对象还是不可变对象,copy 方法返回的对象都是不可变的。

2:集合对象的copy与mutableCopy

实际上,集合对象与非集合对象所遵循的规则基本上是一样的。

可变对象的的copy与mutableCopy 方法

验证代码:

void testSetMutable()  {      NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];      //可变对象copy是深复制      NSMutableArray *array2 = [array1 copy];      //copy返回的是不可变对象,array2不能被修改,因此会崩溃      //[array2 addObject:@"d"];      //可变对象的mutableCopy是深复制      NSMutableArray *array3 = [array1 mutableCopy];      [array3 addObject:@"d"];      NSLog(@"%p %p %p",array1,array2,array3);  }

执行结果:

可以看到地址是不一样的。说明可变对象的copy和mutableCopy方法都是深复制。

不可变对象的copy与mutableCopy方法

验证代码:

void testSetNoMutable()  {      NSArray *array1 = @[@"a",@"b",@"c"];      //不可变对象的copy方法,浅复制      NSArray *array2 = [array1 copy];      //不可变对象的mutableCopy方法,深复制      NSArray *array3 = [array1 mutableCopy];      NSLog(@"%p %p %p",array1,array2,array3);  }

执行结果:

可以看到,前两个地址一样,第三个地址不一样。说明不可变对象的copy方法是浅复制,mutableCopy方法是深复制。

集合对象和非集合对象的一个差别:

上面说的集合对象的深复制并不是严格意义上的深复制,而是单层深复制。

单层深复制:对集合对象来说,深复制时只是将第一层对象进行了深复制,内部的对象仍然是浅复制。比如说

NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];

调用copy方法   NSArray *array2 = [array1 copy] ,有分配了一块内存,array2指向了这块内存,但是数组内部的元素,指向的仍然是数组1内部的元素,即内部元素是浅复制。

验证代码:

void testSetMutable()  {      NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];      //可变对象copy是深复制      NSMutableArray *array2 = [array1 copy];      //copy返回的是不可变对象,array2不能被修改,因此会崩溃      //[array2 addObject:@"d"];      //可变对象的mutableCopy是深复制      NSMutableArray *array3 = [array1 mutableCopy];      [array3 addObject:@"d"];      NSLog(@"%p %p %p",array1,array2,array3);      NSLog(@"%p %p %p",array1[0],array2[0],array3[0]);  }

执行结果:

可以看到,三个数组的第一个元素的地址是一样的,也就是说内部元素是浅复制。

3:集合对象的完全复制

集合对象的完全复制,就是集合中的每一层的元素都是深复制。

方法一:

使用 initWith***: copyItems:YES  方法。

代码:

void testFullCopy()  {      NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];      NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES];      NSLog(@"%p %p",array1,array2);      NSLog(@"%p %p",array1[0],array2[0]);  }

执行结果:

可以看到数组元素的地址不一样。

方法二:

先将集合进行归档,然后再解档。代码如下:

void testFullCopy2()  {      NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];      NSArray *array2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1 ] error:nil];      NSLog(@"%p %p",array1,array2);      NSLog(@"%p %p",array1[0],array2[0]);  }

执行结果:

可以看到数组元素的地址不一样。

来自: http://www.cnblogs.com/acBool/p/5146639.html