服务报价 | 域名主机 | 网络营销 | 软件工具| [加入收藏]
 热线电话: #

iOS中的深复制与浅复制

时间:2016-01-21 00:01来源:未知 作者:最模板 点击:
多语言中都有深复制浅复制的概念,如C++,ObjC等。简单来说,浅复制就是两个变量指向了同一块内存区域,深复制就是两个变量指向了不同的内存区域,但是两个内存区域里面的内容是

多语言中都有深复制浅复制的概念,如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]);
}
复制代码

执行结果:

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

(责任编辑:最模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容