在OC语法中,提供了Copy语法(Copy/MutableCopy)用于对象的拷贝。其中很容易混淆的是浅拷贝和深拷贝。所谓浅拷贝,即单纯的地址拷贝,并不产生新的对象,而是对原对象的引用计数值加1;而深拷贝,即是对象拷贝,产生新的对象副本,拥有独立的内存空间,引用计数器为1。
我们通过一张图先来看看深拷贝与浅拷贝的区别:
我们常用的有NSString/NSMutableString、NSArray/NSMutableArray、NSDictionary/NSMutableDictionary、NSSet、NSMutableSet等系统类对象,下面我们来验证什么情况下是深拷贝,什么情况下是浅拷贝。
NSString *str1 = @"str1"; NSMutableString *str2 = [str1mutableCopy]; NSLog(@"str1=%p str2=%p", str1, str2); NSMutableString *str3 = [[NSMutableString alloc]initWithString:@"sdfsdf"];; NSMutableString *str4 = [str1mutableCopy]; NSLog(@"str3=%p str4=%p", str3, str4); // 打印结果: // str1=0x10516e068 str2=0x7fdd73425bd0 // str3=0x7fdd7373d360 str4=0x7fdd7373a190
从打印结果可以看出来,对于NSString与NSMutableString的mutableCopy:
NSArray *array = @[@"array", @"array1"]; NSMutableArray *array1 = [arraymutableCopy]; NSLog(@"array=%p, array1=%p", array, array1); for (id objin array) { NSLog(@"%p", obj); } for (id objin array1) { NSLog(@"%p", obj); } // 打印结果: array=0x7fdf196055c0, array1=0x7fdf19695fa0 0x105a66088 0x105a660a8 0x105a66088 0x105a660a8
由此可以知道,NSArray对象调用mutableCopy会重新新的可变数组对象,但是可变数组对象的元素并没有独立的内存空间,只是地址的复制而已,因此只是对数组进行了深拷贝,而对数组元素却是进行浅拷贝。这种情况叫做集合的单层深复制 (One-Level-Deep Copy)。
NSDictionary *dict = @{@"key" : @"value", @"key1" : @"value1"}; NSMutableDictionary *dict1 = [dictmutableCopy]; NSLog(@"dict=%p, dict1=%p", dict, dict1); for (id objin dict.allValues) { NSLog(@"%p", obj); } for (id objin dict1.allValues) { NSLog(@"%p", obj); } // 打印结果: dict=0x7f9e70c3a0b0, dict1=0x7f9e70c2f100 0x1021f40a0 0x1021f40e0 0x1021f40a0 0x1021f40e0
从打印结果可以看出来这是NSArray/NSMutableArray的情况是一样的,因此对于NSSet/NSMutableSet自然也是一样的,它们都属于集合类型。
我们来考虑NSString/NSMutableString之间的互相拷贝情况:
NSString *str = @"标哥的技术博客"; // 因为NSString对象本身就不可变,所以并没产生新的对象,而是返回对象本身,但是引用计数加1 NSString *str2 = [strcopy]; // 输出二者的地址,二者的地址是相同的 NSLog(@"str --> %p",str); NSLog(@"str2 --> %p",str2); // 打印结果: str --> 0x10c820068 str2 --> 0x10c820068
从打印结果可以看到地址是一样的,因此它并没有做深拷贝,而是浅拷贝。
NSMutableString *str = [[NSMutableString alloc]initWithString:@"标哥的技术博客"]; NSString *str2 = [strcopy]; NSLog(@"str --> %p",str); NSLog(@"str2 --> %p",str2); // 打印结果: str --> 0x7f9393e0fa90 str2 --> 0x7f9393e7cc10
从打印结果可以看到两个地址不一样,说明发生的是深拷贝。
对于自定义的对象,默认是不遵守NSCopying/NSMutableCopying协议的,如果我们希望自定义对象可以调用copy/mutableCopy,则需要手动去实现。
@interfaceBlog: NSObject<NSCopying> @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *version; @end @implementation Blog // 重写它 - (id)copyWithZone:(NSZone *)zone { Blog *blog = [[Blog alloc]init]; blog.name = self.name; blog.version = self.version; return blog; } @end
测试来测试一下是否可以正常调用copy:
Blog *blog = [[Blog alloc]init]; blog.name = @"标哥的技术博客"; blog.version = @"v1.0.0"; Blog *anotherBlog = [blogcopy]; NSLog(@"blog=%p, anotherBlog=%p", blog, anotherBlog); // blog=0x7ffd13499f50, anotherBlog=0x7ffd1348f3a0
可以正常使用了!调用copy是生成新的对象!
似乎没有见过自定义的遵守NSMutableCopying协议的类型,因为对于可变操作通常是可以执行增、删、改、查操作的类型,最常见的自然是集合类型,还有字符串类型,所以对于自定义类型没有想出在哪些场景需要使用到,故暂不给出例子!
联系方式 | 关注 | 备注 |
---|---|---|
合作联系群 | 347363861 | 接项目、私活 |
iOS直播音视频技术 | 256239496(群6满) | 实名制且群规严,定期清理 |
标哥博客iOS交流群 | 211039962(群7新) | 群里很活跃,定期清理 |
标哥博客iOS交流群 | 324400294(群1满)|494669518(群2满)|494669518(群3满)250351140(群4满)|552095943(群5满) | 群里很活跃,定期清理 |
微信公众号 | iOSDevShares或者iOS开发技术分享 | 关注公众号阅读好文章 |
新浪微博 | @标哥的技术博客 | 关注微博动态 |
GITHUB | CoderJackyHuang | 文章Demo都在GITHUB |
联系标哥 | 关于标哥 | 保持活跃在最前线 |
版权声明:本文为【标哥的技术博客】原创出品,欢迎转载,转载时请注明出处!