博客> iOS深拷贝和浅拷贝,copy与mutableCopy
iOS深拷贝和浅拷贝,copy与mutableCopy
2017-12-13 16:58 评论:1 阅读:548 tianya2416
深拷贝 浅拷贝 copy mutableCopy

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

深拷贝:内存块拷贝,两个内存块完全独立。

浅拷贝:指针拷贝,两个指针指向同一块内存块。

(一) 、关于copy和mutableCopy

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

(二)、NSString、NSMutableString、NSArray、NSMutableArray分别进行copy和mutableCopy时的情况 上面所说的四种结构体可以分为两种类型。 1、系统的非容器类对象 这里指的是NSString,NSNumber等等一类的对象。

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);

内存打印logo:

 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);

内存打印logo:

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

例子一、例子二总结:

对于系统的非容器类对象(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.操作前:

 7A8B1FD5-26BE-4AFC-AA45-6A8C0B581071.png

2.添加一个元素后:

 EADB8CD6-794A-4E71-A19B-650CC4C1B442.png

3.删除一个元素后:

 C2EAC9EE-C703-4CBD-9DB8-CB72921F0F1A.png

总结:

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.修改值之前

 C757C5B6-25BA-4D0E-9E3E-41E93E3FFE8B.png

2.修改值之后

 012B1FF3-884E-4462-BB7A-58E26E87070A.png

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

 638F0D8A-A08B-4D4C-8E42-45061B53E3BF.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];

内存截图

 DA863AB4-6C58-4CE4-9A40-375CCD8F91CA.png

总结:

1.对于容器类本身,与非容器类对象的结论相同,即

如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。

如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。

关键要注意的是复制后容器内对象的变化,比如添加、删除元素,修改某个元素的值。

2.对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现完全深拷贝。

例子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]];

内存截图:

 5EE87385-CB78-4ED8-B975-60329F2F4D0C.png

总结:

1.trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制

2.[deepCopyArray objectAtIndex:0]因为原来是可变对象,还和上面的结论一样,依旧是对象拷贝。

3.用归档的方法实现了真正的元素对象拷贝。

收藏
1
sina weixin mail 回到顶部