iOS浅拷贝、深拷贝和完全深拷贝

1、前言

最近开发中经常遇到这个问题,不过发现网上能完整的总结的还是很少。今天就动手把这个以我的角度总结一下。尽量把问题说明白:

2、概念一

浅拷贝:指针拷贝,两个指针指向同一块内存地址。
深拷贝:内存块拷贝,两个内存地址完全独立或者说完全不同。

2.1、关于copy和mutableCopy

顾名思义,copy就是复制了一个不可变的对象,而mutablecopy就是复制了一个可变的对象。 一个NSObject的对象要想使用这两个函数,那么类必须实现NSCopying协议和NSMutableCopying协议。 对于NSCopying,实现+ copyWithZone:方法。 对于NSMutableCopying,实现+ mutableCopyWithZone:方法。 当然这种情况一般是在自定义结构体时会用,这个我会在后面举例说一下。但经常用的NSString,NSArray,NSDictionary等系统提供的结构体都已实现。

2.2、举个例子
NSString、NSMutableString、NSArray、NSMutableArray分别进行copy和mutableCopy时的情况 上面所说的四种结构体可以分为两种类型。
2.2.1、系统的非容器类对象 这里指的是NSString,NSNumber等等一类的对象。
2.2.2、系统的容器类对象 指NSArray,NSDictionary等。
下面我对对这4种结构体分别进行举例,分为8总情况。我会配上相应的内存截图,以方便阅读。

例子1、对于一个不可变的对象(NSString)
NSString * string = @"weisheng.wang";
NSString * stringCopy = [string copy];
NSString * stringMutableCopy = [string mutableCopy];
NSLog(@"string:%p",string);
NSLog(@"stringCopy:%p",stringCopy);
NSLog(@"stringMutableCopy:%p",stringMutableCopy);

TodayProject[1347:30830] string:0x712c
TodayProject[1347:30830] stringCopy:0x712c
TodayProject[1347:30830] stringMutableCopy:0x79e8d140

例子2、对于一个可变的对象(NSMutableString)
NSMutableString * string =[NSMutableString stringWithFormat:@"weisheng.wang"];
NSString * stringCopy = [string copy];
NSMutableString * stringMutableCopy = [string mutableCopy];
NSLog(@"string:%p",string);
NSLog(@"stringCopy:%p",stringCopy);
NSLog(@"stringMutableCopy:%p",stringMutableCopy);

TodayProject[1508:35092] string:0x7a7890d0
TodayProject[1508:35092] stringCopy:0x7a783400
TodayProject[1508:35092] stringMutableCopy:0x7a786ef0

2.2.3、例子1、例子2总结:

对于系统的非容器类对象(NSString,NSNumber)
如果对一不可变对象进行复制,copy是指针复制(浅拷贝)而mutableCopy就是内存块复制(深拷贝)。
如果是对一可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。

例子3、对NSArray进行copy和mutableCopy操作
NSArray * originArray = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSArray * originArrayCopy = [originArray copy];
NSMutableArray * originArrayMutableCopy = [originArray mutableCopy];
[originArrayMutableCopy addObject:@"d"];
[originArrayMutableCopy removeObjectAtIndex:0];

1、内存截图:
2de5d8c5dcd37f504b9a6d3088244bfb.png

2、添加一个元素后:
添加一个元素后.png
3、删除一个元素后
171a3558c9c695556288677e4badad98.png

2.2.4、例子3总结:

originArray和originArrayCopy是浅复制,而originArrayMutableCopy是深拷贝,originArrayMutableCopy还可以改变数组内的元素:删除或添加。但是注意的是,容器内的元素内容都是浅拷贝。

例子4、修改元素的值
NSArray * originArray = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];
NSArray * originArrayCopyArray = [originArray copy];
NSMutableArray * originArrayMutableCopyArray = [originArray mutableCopy];
// originArrayMutableCopyArray,originArrayCopyArray和originArray其中的元素都是一样的对象——同一个指针
//注意:这里只能是将值先取出来通过append来修改,如果用testString = @"d";这样会改变testString的指针,其实是将@“d”临时对象赋给了testString
NSMutableString * testString = [originArray objectAtIndex:0];
[testString appendString:@" changevalue"];// 这样以上三个数组的首元素都被改变了

内存截图

1、修改值之前
f7fdf23fbd165cda4d17b49ba61fdaa4.png
2、修改值之后
43803eb224bdb298d02f3c955be4b93d.png

3、用testString = @"d"修改值后内存情况,这样以数组中的元素没有任何影响,当然也没有任何意义
6f2baa450093b3b862dba6dd616d9d64.png

例子5:对NSMutableArray进行copy和mutableCopy操作
NSMutableArray *originArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"c", nil];
NSArray *originArrayCopy = [originArray copy];
NSMutableArray *originArrayCopy1 = [originArray copy];
[originArrayCopy1 addObject:@"d"];//mutable对象copy之后成为imutable对象,所以添加元素会error
NSMutableArray *originArrayMutableCopy = [originArray mutableCopy];

内存截图
7e9f01616e6ef74bc79124e0edfb5611.png

2.2.4、例子4、例子5总结:
1.对于容器类本身,与非容器类对象的结论相同,即
如果对一不可变对象进行复制,copy是指针复制(浅拷贝)而mutableCopy就是对象复制(深拷贝)。
如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
关键要注意的是复制后容器内对象的变化,比如添加、删除元素,修改某个元素的值。
2.对于容器而言,其元素对象始终是指针拷贝(浅拷贝)。如果需要元素对象也是深拷贝,就需要实现完全深拷贝。

3、概念二
完全深拷贝:指的是容器本身的地址和容器内元素的地址 不一样

例子6、完全深拷贝的一种实现
NSArray * array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],[NSString stringWithString:@"b"],@"c",nil];
NSArray * deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];

内存截图:
51d3e7bd2d0c2378fcfa71b62d035699.png

3.1 例子6总结
1.trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的元素还是浅拷贝
2.[deepCopyArray objectAtIndex:0]因为原来是可变对象,还和上面的结论一样,依旧是深拷贝。
3.用归档的方法实现了真正的元素深拷贝。

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