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_对象:(
    "<NSObject: 0x600001384c50>"
)_引用计数:1
2019-12-17 14:48:05.655102+0800 CopyTest[6223:303565] 注释:CopyArray_指针地址:0x7ffeee88ca08_对象地址:0x600001384c60_对象:(
    "<NSObject: 0x600001384c50>"
)_引用计数:2
2019-12-17 14:48:05.655236+0800 CopyTest[6223:303565] 注释:MutableCopyArray_指针地址:0x7ffeee88ca00_对象地址:0x600001fc5b60_对象:(
    "<NSObject: 0x600001384c50>"
)_引用计数:1
2019-12-17 14:48:05.655349+0800 CopyTest[6223:303565] 注释:Array_指针地址:0x7ffeee88ca10_对象地址:0x600001191dc0_对象:(
    "<NSObject: 0x600001384c50>",
    "<NSObject: 0x600001384c50>"
)_引用计数:1
2019-12-17 14:48:05.655451+0800 CopyTest[6223:303565] 注释:CopyArray_指针地址:0x7ffeee88ca08_对象地址:0x600001384c60_对象:(
    "<NSObject: 0x600001384c50>"
)_引用计数:2
2019-12-17 14:48:05.655525+0800 CopyTest[6223:303565] 注释:MutableCopyArray_指针地址:0x7ffeee88ca00_对象地址:0x600001fc5b60_对象:(
    "<NSObject: 0x600001384c50>"
)_引用计数: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_对象:(
    "<NSObject: 0x600002da7700>"
)_引用计数:1
2019-12-17 14:53:26.402298+0800 CopyTest[6368:322462] 注释:CopyMutableArray_指针地址:0x7ffeed6b5a28_对象地址:0x600002da7710_对象:(
    "<NSObject: 0x600002da7700>"
)_引用计数:1
2019-12-17 14:53:35.683280+0800 CopyTest[6368:322462] 注释:MutableCopyMutableArray_指针地址:0x7ffeed6b5a20_对象地址:0x6000021e61f0_对象:(
    "<NSObject: 0x600002da7700>"
)_引用计数:1
2019-12-17 14:53:40.723298+0800 CopyTest[6368:322462] 注释:MutableArray_指针地址:0x7ffeed6b5a30_对象地址:0x6000021f9f20_对象:(
    "<NSObject: 0x600002da7700>",
    "<NSObject: 0x600002da7700>"
)_引用计数:1
2019-12-17 14:53:47.418461+0800 CopyTest[6368:322462] 注释:CopyMutableArray_指针地址:0x7ffeed6b5a28_对象地址:0x600002da7710_对象:(
    "<NSObject: 0x600002da7700>"
)_引用计数:1
2019-12-17 14:53:50.173948+0800 CopyTest[6368:322462] 注释:MutableCopyArray_指针地址:0x7ffeed6b5a20_对象地址:0x6000021e61f0_对象:(
    "<NSObject: 0x600002da7700>"
)_引用计数:1

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容