天天看点

copy与mutableCopy 记住:

记住:

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

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

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

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

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

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

(一)关于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];
           

内存截图:

copy与mutableCopy 记住:

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

内存截图:

copy与mutableCopy 记住:

总结:

对于系统的非容器类对象,

如果对一不可变对象复制,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.操作前:

copy与mutableCopy 记住:

2.添加一个元素后:

copy与mutableCopy 记住:

3.删除一个元素后:

copy与mutableCopy 记住:

不知我的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.修改值之前

copy与mutableCopy 记住:

2.修改值之后

copy与mutableCopy 记住:

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

copy与mutableCopy 记住:

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

内存截图

copy与mutableCopy 记住:

总结:

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

           

内存截图:

copy与mutableCopy 记住:

总结:

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

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

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

4.记得在iphone3开发基础教程上也有深拷贝的一个方法,下次再总结上来。

继续阅读