美文网首页技术iOS学习
深拷贝、浅拷贝的理解与使用场景

深拷贝、浅拷贝的理解与使用场景

作者: Leafly | 来源:发表于2017-10-30 19:28 被阅读680次

什么是深拷贝、浅拷贝?

通俗解释:深拷贝是内容拷贝,浅拷贝是地址拷贝

区别点:

深拷贝会创建一个新的内存空间,拷贝的值是一样的,但是内存地址不一样。
浅拷贝只是拷贝指向原来对象的地址,使原对象的引用计数+1

容器类对象与非容器类对象在深拷贝、浅拷贝方面的异同点?

什么是容器类对象?什么是非容器类对象?

像NSString、NSNumber这些不能包含其他对象的叫做非容器类对象
像NSArray、NSDictionary这些可以包含其他对象的叫容器类对象

不可变对象NSString

NSString *string1 = @"helloworld";  
NSString *string2 = [string1 copy]; // 浅拷贝  
NSString *string3 = [string1 mutableCopy]; // 深拷贝  
NSMutableString *string4 = [string1 copy]; // 浅拷贝  此处需要注意copy返回的是不可变对象,string4不能被修改 否则会发生崩溃
NSMutableString *string5 = [string1 mutableCopy]; // 深拷贝  
  
NSLog(@"string1 = %d;string2 = %d",string1,string2);  
NSLog(@"string1 = %d;string3 = %d",string1,string3);  
NSLog(@"string1 = %d;string4 = %d",string1,string4);  
NSLog(@"string1 = %d;string5 = %d",string1,string5);  

打印结果如下:

通过对比不难发现:

  • 如果右侧是copy则是浅拷贝
  • 如果右侧是mutableCopy则是深拷贝

可变对象NSMutableString

上面我们使用的是不可变的NSString,下面我们再使用可变的NSMutableString对比一下:

// 如果是一个MutableString,那么无论是copy,mutableCopy,都会创建一个新对象。  
   NSMutableString *string1 = [NSMutableString stringWithString:@"helloworld"];  
   NSString *string2 = [string1 copy]; // 深拷贝  
   NSString *string3 = [string1 mutableCopy]; // 深拷贝  
   NSMutableString *string4 = [string1 copy]; // 深拷贝  此处需要注意copy返回的是不可变对象,string4不能被修改 否则会发生崩溃
   NSMutableString *string5 = [string1 mutableCopy]; // 深拷贝  
  
   NSLog(@"string1 = %d;string2 = %d",string1,string2);  
   NSLog(@"string1 = %d;string3 = %d",string1,string3);  
   NSLog(@"string1 = %d;string4 = %d",string1,string4);  
   NSLog(@"string1 = %d;string5 = %d",string1,string5);  

打印结果如下:

不难发现,对于NSMutableString, 无论是copy还是mutableCopy都会创建一个新对象,属于深拷贝

不可变对象NSArray

NSArray *array01 = [NSArray arrayWithObjects:@"a",@"b",@"c", nil nil];  
NSArray *copyArray01 = [array01 copy];  
NSMutableArray *mutableCopyArray01 = [array01 mutableCopy];  
   
NSLog(@"array01 = %d,copyArray01 = %d",array01,copyArray01);  
NSLog(@"array01 = %d,mutableCopyArray01 = %d",array01,mutableCopyArray01);  
  
NSLog(@"array01[0] = %d,array01[1] = %d,array01[2] = %d",array01[0],array01[1],array01[2]);  
NSLog(@"copyArray01[0] = %d,copyArray01[1] = %d,copyArray01[2] = %d",copyArray01[0],copyArray01[1],copyArray01[2]);  
NSLog(@"mutableCopyArray01[0] = %d,mutableCopyArray01[1] = %d,mutableCopyArray01[2] = %d",mutableCopyArray01[0],mutableCopyArray01[1],mutableCopyArray01[2]);  

打印结果如下:

不难发现,copy是浅拷贝,mutableCopy是深拷贝,不过需要注意的是容器对象的成员元素都指向相同的地址

可变对象NSMutableArray

NSMutableArray *array01 = [NSMutableArray arrayWithObjects:@"a",@"b",@"c", nil nil];  
NSArray *copyArray01 = [array01 copy];  
NSMutableArray *mutableCopyArray01 = [array01 mutableCopy];  

NSLog(@"array01 = %d,copyArray01 = %d",array01,copyArray01);  
NSLog(@"array01 = %d,mutableCopyArray01 = %d",array01,mutableCopyArray01);  
NSLog(@"array01[0] = %d,array01[1] = %d,array01[2] = %d",array01[0],array01[1],array01[2]);  
NSLog(@"copyArray01[0] = %d,copyArray01[1] = %d,copyArray01[2] = %d",copyArray01[0],copyArray01[1],copyArray01[2]);  
NSLog(@"mutableCopyArray01[0] = %d,mutableCopyArray01[1] = %d,mutableCopyArray01[2] = %d",mutableCopyArray01[0],mutableCopyArray01[1],mutableCopyArray01[2]);  

打印结果如下:

对比可见,容器对象与非容器对象类似,可变对象的复制都是深拷贝,不可变对象copy是浅拷贝,mutableCopy是深拷贝
需要注意的是对容器而言,元素对象始终是指针复制

如何实现容器对象的完全深拷贝?

正如前面所说,容器对象中的元素对象无论是copy还是mutableCopy都是指针复制,如何实现容器对象的完全深拷贝呢?

系统API

系统为我们实现容器对象的完全深拷贝提供了方法

- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag

// 使用方式如下:

- (void)fullCopy {
    NSMutableArray *marray1 = [[NSMutableArray alloc] init];
    
    NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
    NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
    
    [marry1 addObject:mstr1];
    [marry1 addObject:mstr2];
    
    NSArray *marray2 = [[NSArray alloc] initWithArray:marry1 copyItems:YES];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);
    NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}

归档解档方法

- (void) deplyFullCopy
{
    NSMutableArray *marry1 = [[NSMutableArray alloc] init];
    
    NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
    NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
    
    [marry1 addObject:mstr1];
    [marry1 addObject:mstr2];
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:marry1];
    NSArray *marray2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);
    NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}

自定义类如何实现深、浅拷贝

  • 要想实现对象的自定义拷贝,必须实现NSCopying,NSMutableCopying协议,实现该协议的copyWithZone方法和mutableCopyWithZone方法
@interface Person()<NSCopying, NSMutableCopying>  
  
@end  
  
@implementation Person  
  
// 对应copy方法  
- (id)copyWithZone:(NSZone *)zone  
{  
    Person *person = [[Person allocWithZone:zone] init];  
    person.name = self.name; // 这里的self就是被copy的对象  
    person.age = self.age;  
    return person;  
}  
  
- (id)mutableCopyWithZone:(NSZone *)zone  
{  
    Person *person = [[Person allocWithZone:zone] init];  
    person.name = self.name;  
    person.age = self.age;  
    return person;  
}  
  
  
@end  

使用场景

  • 在声明字符串属性时尽量使用copy,如果使用strong声明属性,那么当源字符串发生改变时,对应的属性值也会发生改变,因为他们指向同一个地址,而使用copy就能杜绝这种情况,因为对于可变字符串进行copy是深拷贝,而strong只表示持有对象,引用计数加一。

相关文章

  • iOS之深拷贝与浅拷贝

    深拷贝与浅拷贝是在内存管理中非常重要的概念,理解好深拷贝和浅拷贝也有助于加深对iOS的内存管理的理解。 深拷贝与浅...

  • iOS 深浅拷贝

    iOS深拷贝与浅拷贝的区别 深拷贝与浅拷贝的概念:(我的理解,望不吝赐教) 浅拷贝:只copy一份对象的指针,指向...

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

  • 深浅拷贝,面向对象,Symbol,Set,Map

    一:浅拷贝与深拷贝对象的浅拷贝:浅拷贝是对象共用的一个内存地址,对象的变化相互影响。对象的深拷贝:简单理解深拷贝是...

  • 深拷贝、浅拷贝的理解与使用场景

    什么是深拷贝、浅拷贝? 通俗解释:深拷贝是内容拷贝,浅拷贝是地址拷贝 区别点: 深拷贝会创建一个新的内存空间,拷贝...

  • 高级二.深浅copy

    1. ==,is的使用 2.拷贝 2.1 浅拷贝与深拷贝 浅拷贝是对于一个对象...

  • python中的拷贝

    Python中的拷贝分为两种,浅拷贝与深拷贝 浅拷贝:浅拷贝是对于一个对象的顶层拷贝。通俗的理解是:拷贝了引用,并...

  • JS中的深拷贝与浅拷贝

    知乎:js中的深拷贝和浅拷贝? 掘金: js 深拷贝 vs 浅拷贝 前言 首先深拷贝与浅拷贝只针对 Object,...

  • “深拷贝” 与 “浅拷贝” 的区别,JS实现深浅拷贝的几种方法

    一、 “深拷贝” 与 “浅拷贝” 的区别 对于这个问题,可以考虑从深拷贝和浅拷贝的使用或者起源说起,也就是为什么会...

  • 深拷贝、浅拷贝

    深拷贝、浅拷贝 1. 浅拷贝 浅拷贝是对于一个对象的顶层拷贝 通俗的理解是:拷贝了引用,并没有拷贝内容 2. 深拷...

网友评论

    本文标题:深拷贝、浅拷贝的理解与使用场景

    本文链接:https://www.haomeiwen.com/subject/tnempxtx.html