copy与mutableCopy

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

(一)关于copy和mutableCopy
顾名思义,copy就是复制了一个imutable的对象,而mutablecopy就是复制了一个mutable的对象。
一个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进行copy和mutableCopy操作

NSString *originStr = @"origin";
NSString *originStrCopy = [originStr copy];
NSMutableString *originStrMutableCopy = [originStr mutableCopy];

内存截图:
NSString

例2:对NSMutableString进行copy和mutableCopy操作

NSMutableString *mutableOriginStr =[NSMutableString stringWithString: @"mutableOrigin"];
//注意这里下面两行代码前面的声明
NSString *mutableOriginStrCopy = [mutableOriginStr copy];
NSMutableString *mutableOriginStrCopy1 = [mutableOriginStr copy];
//这里会报错,因为copy生成的是imutable对象,所以不管声明是什么样的,依旧是imutable的
[mutableOriginStrCopy1 appendString:@"error"];
NSMutableString *mutableOriginStrMutableCopy = [mutableOriginStr mutableCopy];

内存截图:
NSMutableString
总结:
对于系统的非容器类对象,
如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。
如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。

例3:对NSArray进行copy和mutableCopy操作

NSArray *originArray = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSArray *originArrayCopy = [originArray copy];
//originArray是和originArray同一个NSArray对象(指向相同的对象),包括originArray里面的元素也是指向相同的指针,此处可以看到copy的作用也相当于retain
NSLog(@"originArray retain count: %ld",(unsigned long)[originArray retainCount]);
NSLog(@"originArray retain count: %ld",(unsigned long)[originArrayCopy retainCount]);
NSMutableArray *originArrayMutableCopy = [originArray mutableCopy];
//originArrayMutableCopy是originArray的可变副本,指向的对象和originArray不同,但是其中的元素和originArray中的元素指向的是同一个对象。originArrayMutableCopy还可以修改自己的对象
[originArrayMutableCopy addObject:@"d"];
[originArrayMutableCopy removeObjectAtIndex:0];

内存截图:
1.操作前:
NSArray
2.添加一个元素后:
添加元素后
3.删除一个元素后:
删除一个元素
不知我的xcode怎么回事,对于originArrayMutableCopy显示貌似有点问题,打出来结果如下:

2013-03-21 16:08:08.885 MemoryTest[52329:303] originArrayMutableCopy (
    b,
    c,
    d
)

总结:
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.修改值之前
NSArray
2.修改值之后
NSArray修改元素的值
3.用testString = @"d"修改值后内存情况,这样以数组中的元素没有任何影响,当然也没有任何意义
NSArray修改元素的值

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

内存截图
NSMutableArray
总结:
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]];

内存截图:
容器对象的深拷贝

总结:
1.trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制
2.[deepCopyArray objectAtIndex:0]因为原来是可变对象,还和上面的结论一样,依旧是对象拷贝。
3.用归档的方法实现了真正的元素对象拷贝。
4.记得在iphone3开发基础教程上也有深拷贝的一个方法,下次再总结上来。

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部