iOS Copy

一、拷贝对象的基本概念

拷贝一个对象的副本,开辟一块新的内存来存储副本对象

二、浅拷贝和深拷贝

1、浅拷贝

浅拷贝就是对对象内存地址的拷贝,让目标指针和源指针指向同一片内存空间。
浅拷贝只是对对象的简单拷贝,让几个指针共用一片内存,当内存销毁的时候,指向这片内存的几个指针需要重新定义才可以使用,不然会成为野指针。
在iOS中,使用retain,是一种更加保险的浅拷贝。它让几个指针共用同一块内存空间。 由于引用计数的存在,不会轻易的销毁内存,达到更加简单使用的目的。

2、深拷贝

深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。

三、协议

如果一个对象想具备拷贝的功能,必须实现协议。
NSObject自带的常用的对象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableString、NSMutableArray、NSMutableDictionary
iOS提供了copy和mutableCopy方法,顾名思义,copy就是复制了一个imutable的对象,而mutableCopy就是复制了一个mutable的对象。
当然在iOS中并不是所有的对象都支持copy和mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutableCopying 协议的类才可以发送mutableCopy消息。假如发送了一个没有遵守上述两协议而发送copy或者mutableCopy,那么就会发生异常。但是默认的iOS类并没有遵守这两个协议。如果想自定义copy就必须遵守NSCopying,并且实现copyWithZone:方法,如果想自定义mutableCopy就必须遵守NSMutableCopying,并且实现mutableCopyWithZone:方法。

四、copy和retain的区别

copy是创建一个对象,retain是创建一个指针。
copy属性表示两个对象内容相同,新的对象引用计数为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。
retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的引用计数+1。
也就是说,retain 是指针拷贝(浅拷贝),copy 是对象拷贝(深拷贝)。

五、探究

#define MyLog(Comment, Obj) NSLog(@"注释:%@_指针地址:%p_对象地址:%p_对象:%@_引用计数:%ld", Comment, &Obj, Obj, Obj, [Obj retainCount]);

1、系统的非容器类对象

(NSString,NSNumber等一类的对象)

1.1、不可变对象

NSString *string = @"Hello";
MyLog(@"String", string);
NSString *copyString = [string copy];
MyLog(@"CopyString", copyString);
NSString *mutableCopyString = [string mutableCopy];
MyLog(@"MutableCopyString", mutableCopyString);
    
string = @"World";
MyLog(@"String", string);
MyLog(@"CopyString", copyString);
MyLog(@"MutableCopyString", mutableCopyString);
2019-12-17 14:13:05.888336+0800 CopyTest[5239:233232] 注释:String_指针地址:0x7ffeee082a38_对象地址:0x101b7c050_对象:Hello_引用计数:-1
2019-12-17 14:13:07.112412+0800 CopyTest[5239:233232] 注释:CopyString_指针地址:0x7ffeee082a30_对象地址:0x101b7c050_对象:Hello_引用计数:-1
2019-12-17 14:13:10.228491+0800 CopyTest[5239:233232] 注释:MutableCopyString_指针地址:0x7ffeee082a28_对象地址:0x600003558990_对象:Hello_引用计数:1
2019-12-17 14:13:16.821985+0800 CopyTest[5239:233232] 注释:String_指针地址:0x7ffeee082a38_对象地址:0x101b7c0f0_对象:World_引用计数:-1
2019-12-17 14:13:25.889237+0800 CopyTest[5239:233232] 注释:CopyString_指针地址:0x7ffeee082a30_对象地址:0x101b7c050_对象:Hello_引用计数:-1
2019-12-17 14:13:58.920537+0800 CopyTest[5239:233232] 注释:MutableCopyString_指针地址:0x7ffeee082a28_对象地址:0x600003558990_对象:Hello_引用计数:1

查看Log可发现,string和copyString指向的是同一块内存区域。而mutableCopyString则是我们所说的真正意义上的拷贝,系统为其分配了新内存,引用计数为1,指针所指向的字符串内容和string所指的一样。

1.2、可变对象

NSMutableString *mutableString = [NSMutableString stringWithFormat:@"Hello"];
MyLog(@"MutableString", mutableString);
NSString *copyMutableString = [mutableString copy];
MyLog(@"CopyMutableString", copyMutableString);
NSString *mutableCopyMutableString = [mutableString mutableCopy];
MyLog(@"MutableCopyMutableString", mutableCopyMutableString);
    
mutableString = [NSMutableString stringWithFormat:@"World"];
MyLog(@"MutableString", mutableString);
MyLog(@"CopyMutableString", copyMutableString);
MyLog(@"MutableCopyMutableString", mutableCopyMutableString);
2019-12-17 14:22:47.659570+0800 CopyTest[5512:258797] 注释:MutableString_指针地址:0x7ffee358ea38_对象地址:0x600002204c00_对象:Hello_引用计数:1
2019-12-17 14:22:49.269361+0800 CopyTest[5512:258797] 注释:CopyMutableString_指针地址:0x7ffee358ea30_对象地址:0x8d16218c3feb7c2b_对象:Hello_引用计数:-1
2019-12-17 14:22:53.712337+0800 CopyTest[5512:258797] 注释:MutableCopyMutableString_指针地址:0x7ffee358ea28_对象地址:0x600002254000_对象:Hello_引用计数:1
2019-12-17 14:22:58.449147+0800 CopyTest[5512:258797] 注释:MutableString_指针地址:0x7ffee358ea38_对象地址:0x600002204ab0_对象:World_引用计数:1
2019-12-17 14:23:06.121620+0800 CopyTest[5512:258797] 注释:CopyMutableString_指针地址:0x7ffee358ea30_对象地址:0x8d16218c3feb7c2b_对象:Hello_引用计数:-1
2019-12-17 14:23:09.417593+0800 CopyTest[5512:258797] 注释:MutableCopyMutableString_指针地址:0x7ffee358ea28_对象地址:0x600002254000_对象:Hello_引用计数:1

copy产生的对象是不可变的,mutableCopy产生的对象是可变的
对于系统的非容器类对象,我们可以认为,如果对一不可变对象拷贝,copy是指针拷贝(浅拷贝),mutableCopy就是对象拷贝(深拷贝)。如果是对可变对象拷贝,都是深拷贝,但是copy返回的对象是不可变的。

2、系统的容器类对象

(NSArray,NSDictionary等一类的对象, 对于容器类本身,上面讨论的结论也是适用的,需要探讨的是拷贝后容器内对象的变化。)

2.1、不可变对象

NSObject *object = [[NSObject alloc] init];
NSArray *array = @[object];
MyLog(@"Array", array);
NSArray *copyArray = [array copy];
MyLog(@"CopyArray", copyArray);
NSMutableArray *mutableCopyArray = [array mutableCopy];
MyLog(@"MutableCopyArray", mutableCopyArray);
    
array = @[object, object];
MyLog(@"Array", array);
MyLog(@"CopyArray", copyArray);
MyLog(@"MutableCopyArray", mutableCopyArray);
2019-12-17 14:48:05.654817+0800 CopyTest[6223:303565] 注释:Array_指针地址:0x7ffeee88ca10_对象地址:0x600001384c60_对象:(
    ""
)_引用计数:1
2019-12-17 14:48:05.655102+0800 CopyTest[6223:303565] 注释:CopyArray_指针地址:0x7ffeee88ca08_对象地址:0x600001384c60_对象:(
    ""
)_引用计数:2
2019-12-17 14:48:05.655236+0800 CopyTest[6223:303565] 注释:MutableCopyArray_指针地址:0x7ffeee88ca00_对象地址:0x600001fc5b60_对象:(
    ""
)_引用计数:1
2019-12-17 14:48:05.655349+0800 CopyTest[6223:303565] 注释:Array_指针地址:0x7ffeee88ca10_对象地址:0x600001191dc0_对象:(
    "",
    ""
)_引用计数:1
2019-12-17 14:48:05.655451+0800 CopyTest[6223:303565] 注释:CopyArray_指针地址:0x7ffeee88ca08_对象地址:0x600001384c60_对象:(
    ""
)_引用计数:2
2019-12-17 14:48:05.655525+0800 CopyTest[6223:303565] 注释:MutableCopyArray_指针地址:0x7ffeee88ca00_对象地址:0x600001fc5b60_对象:(
    ""
)_引用计数:1

copyArray是指针拷贝,而mutableCopyArray是对象拷贝,mutableCopyArray还可以改变内部的元素:删除或添加。但是注意的是,容器内的元素内容都是指针拷贝。

2.2、可变对象

NSObject *object = [[NSObject alloc] init];
NSMutableArray *mutableArray = [NSMutableArray arrayWithObject:object];
MyLog(@"MutableArray", mutableArray);
NSArray *copyMutableArray = [mutableArray copy];
MyLog(@"CopyMutableArray", copyMutableArray);
NSMutableArray *mutableCopyMutableArray = [mutableArray mutableCopy];
MyLog(@"MutableCopyMutableArray", mutableCopyMutableArray);
    
[mutableArray addObject:object];
MyLog(@"MutableArray", mutableArray);
MyLog(@"CopyMutableArray", copyMutableArray);
MyLog(@"MutableCopyArray", mutableCopyMutableArray);
2019-12-17 14:53:20.011397+0800 CopyTest[6368:322462] 注释:MutableArray_指针地址:0x7ffeed6b5a30_对象地址:0x6000021f9f20_对象:(
    ""
)_引用计数:1
2019-12-17 14:53:26.402298+0800 CopyTest[6368:322462] 注释:CopyMutableArray_指针地址:0x7ffeed6b5a28_对象地址:0x600002da7710_对象:(
    ""
)_引用计数:1
2019-12-17 14:53:35.683280+0800 CopyTest[6368:322462] 注释:MutableCopyMutableArray_指针地址:0x7ffeed6b5a20_对象地址:0x6000021e61f0_对象:(
    ""
)_引用计数:1
2019-12-17 14:53:40.723298+0800 CopyTest[6368:322462] 注释:MutableArray_指针地址:0x7ffeed6b5a30_对象地址:0x6000021f9f20_对象:(
    "",
    ""
)_引用计数:1
2019-12-17 14:53:47.418461+0800 CopyTest[6368:322462] 注释:CopyMutableArray_指针地址:0x7ffeed6b5a28_对象地址:0x600002da7710_对象:(
    ""
)_引用计数:1
2019-12-17 14:53:50.173948+0800 CopyTest[6368:322462] 注释:MutableCopyArray_指针地址:0x7ffeed6b5a20_对象地址:0x6000021e61f0_对象:(
    ""
)_引用计数:1

由此可见,对于容器而言,其元素对象始终是指针拷贝。如果需要元素对象也是对象拷贝,就需要自己实现深拷贝。

你可能感兴趣的:(iOS Copy)