OC学习笔记——深拷贝与浅拷贝

copy与mutableCopy

copy在OC中起到复制的作用,是一个通过源对象产生副本对象的过程,OC中可以使用copy或mutableCopy创建一个副本对象。

copy

创建不可变副本(如NSString、NSArray、NSDictionary)
使用时要遵守NSCopying协议,实现copyWithZone:方法

@protocol NSCopying

- (id)copyWithZone:(NSZone *)zone;

@end

mutableCopy

创建可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
使用时要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法

@protocol NSMutableCopying

- (id)mutableCopyWithZone:(NSZone *)zone;

@end

深拷贝与浅拷贝

在这里插入图片描述
深拷贝是对整个对象的拷贝,而浅拷贝仅仅是对于指针的拷贝。左图中,AB指针指向同一个对象,为浅拷贝;右图中不仅新建了指针B,还将对象进行了复制,这就是浅拷贝。

我们知道OC中的三种容器:数组(array),字典(dictionary)和集合(set)。在OC中对于容器与非容器的拷贝机制并不相同。

非容器不可变对象(NSString为例)

NSString *str1 = @"非容器不可变对象";
NSString *str2 = [str1 copy];
NSString *str3 = [str1 mutableCopy];
    
NSLog(@"str1_p : %p, class: %@", str1, [str1 class]);
NSLog(@"str2_p : %p, class: %@", str2, [str2 class]);
NSLog(@"str3_p : %p, class: %@", str3, [str3 class]);

输出:
在这里插入图片描述

结果:

  1. 非容器不可变对象的copy为浅拷贝,mutableCopy为深拷贝
  2. copy的浅拷贝对象地址与原对象地址一样,返回的对象为不可变对象
  3. mutableCopy的深拷贝返回新的内存地址,返回对象为可变对象

非容器可变对象(NSMutableString为例)

NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
NSMutableString *str2 = [str1 copy];
NSMutableString *str3 = [str1 mutableCopy];
    
NSLog(@"str1_p : %p, class: %@", str1, [str1 class]);
NSLog(@"str2_p : %p, class: %@", str2, [str2 class]);
NSLog(@"str3_p : %p, class: %@", str3, [str3 class]);

输出:
在这里插入图片描述
结果:

  1. 非容器可变对象的copy和mutableCopy都为深拷贝
  2. 二者返回对象都为可变对象

容器不可变对象(NSArray为例)

NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
        
NSArray *array = [NSArray arrayWithObjects:str1, @"非容器不可变对象", nil];
NSArray *copyArray = [array copy];
NSArray *mutableCopyArray = [array mutableCopy];
        
NSLog(@"======array与copyArray=====");
NSLog(@"array_p: %p, class: %@", array, [array class]);
NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);

NSLog(@"======原对象=====");
NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);

NSLog(@"======copy对象=====");
NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);

NSLog(@"======mutableCopy对象=====");
NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);

输出:
在这里插入图片描述
结果:

  1. 容器不可变对象的copyArray为浅拷贝,mutableCopyArray为深拷贝
  2. mutableCopyArray虽然是深拷贝,但容器内元素仍为浅拷贝

容器可变对象

NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];

NSLog(@"======array与copyArray=====");
NSMutableArray *array = [NSMutableArray arrayWithObjects:str1, @"非容器不可变对象", nil];
NSMutableArray *copyArray = [array copy];
NSMutableArray *mutableCopyArray = [array mutableCopy];

NSLog(@"array_p: %p, class: %@", array, [array class]);
NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);

NSLog(@"======原对象=====");
NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);

NSLog(@"======copy对象=====");
NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);

NSLog(@"======mutableCopy对象=====");
NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);

输出:
在这里插入图片描述
结果:

  1. 容器可变对象的copyArray和mutableCopyArray都为深拷贝
  2. 二者容器内元素都为浅拷贝

总结

  1. copy对于可变对象为深拷贝,对于不可变对象为浅拷贝;mutableCopy始终是深拷贝
  2. 对容器进行拷贝,容器内元素始终为浅拷贝

one more thing

OC的对象拷贝其实有三种方式:

  • 浅复制(shallow copy):在浅复制操作时,对于被复制对象的每一层都是指针复制。
  • 深复制(one-level-deep copy):在深复制操作时,对于被复制对象,至少有一层是深复制。
  • 完全复制(real-deep copy):在完全复制操作时,对于被复制对象的每一层都是对象复制。

有时候我们将深复制和完全复制混为一谈,但它们其实是有区别的。“深复制实现难度大”,其实是完全复制实现难度大,因为完全复制需要复制对象的每一层,当指针结构复杂时,难度可想而知。通常实现完全复制的方法只有迭代和归档。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值