Apple官方文档如下:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html
最近用Core Data做数据管理,Fetch到NSArray类型的结果数组,为了能够进行增、删、改,我把它MutableCopy到一个NSMutableArray数组中。增加、删除用manageModelsContext中的接口操作即可,修改则把NSArray结果中需要修改的实例取出来进行更改,然后用manageModelsContext保存即可完成修改到sqlite文件。
可是问题是我发现用MutableCopy得到的数组中取出的元素直接修改后保存,也能完成修改操作。于是就产生了这样的一个疑问:MutableCopy是浅拷贝??再下来我就发现copy相关的东西我还完全没有搞清楚。
首先关于copy和mutableCopy的行为:不管是NSString这种元素类、还是NSArray这样的容器类、还是Mutable和非Mutable类,copy和mutableCopy调用后表现的行为到底是什么样完成取决于类本身NSCopying和NSMutableCopying协议是如何实现的。
想要正常调用copy和mutableCopy两个函数,那么类就一定要实现对应的协议。
1. 元素数据的copy和mutableCopy。
常用的NSString类,示例代码如下:
- NSString* string = @”a”;
- NSString* stringCopy = [string copy];
- NSMutableString* stringMCopy = [string mutablecopy];
-
- NSMutableString* stringM1 = [stringMCopy copy];
- NSMutableString* stringM2 = [stringMCopy mutablecopy];
可以基本推出NSString和NSMutableString中两个协议的实现
- NSString:
- - (id)copywithZone:(NSZone*)zone
- {
- return self;
- }
-
- - (id)mutableCopywithZone:(NSZone*)zone
- {
- NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];
- ....
- return copy;
- }
- NSMutableString:
- - (id)copywithZone:(NSZone*)zone
- {
- NSString* copy = [[NSStringalloc] initxxxxxx];
- ....
- return copy;
- }
-
- - (id)mutableCopywithZone:(NSZone*)zone
- {
- NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];
- ....
- return copy;
- }
2. 容器类的copy和mutableCopy。
常用类NSArray和NSMutableArray,看如下示例代码:
- Class1* obj1= ....;
- NSArray* array = [[NSArray alloc] initWithObjects:obj1, nil];
- NSArray* arrayCopy = [array copy];
- NSMutableArray* arrayMCopy = [array mutableCopy];
-
- NSMutableArray* arrayM1 = [arrayMCopy Copy];
- NSMutableArray* arrayM2 = [arrayMCopy mutableCopy];
- NSArray:
- - (id)copywithZone:(NSZone*)zone
- {
-
- return [self retain];
- }
-
- - (id)mutableCopywithZone:(NSZone*)zone
- {
- NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];
- for (id element in self) {
- [copy addObject:element];
- ....
- }
- return copy;
- }
-
- NSMutableArray:
- - (id)copywithZone:(NSZone*)zone
- {
- NSArray* copy = [[NSArray alloc] initXXX];
-
- ....
- return copy;
- }
-
- - (id)mutableCopywithZone:(NSZone*)zone
- {
- NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];
- for (id element in self) {
- [copy addObject:element];
- ....
- }
- return copy;
- }
3. 深拷贝
上面提到的官方文档中介绍两种实现深拷贝的方法:
a. 用Array的initWithArray: copyItems函数,如下:
NSArray *deepCopyArray=[[NSArray alloc] initWithArray: someArraycopyItems: YES];
调用后,会对原NSArray中的每个元素调用其copy函数,并把返回的id加入到新的数组中。所以这是依赖于Obj对象类实现的深拷贝,如果- (id)copywithZone:(NSZone*)zone是重新分配一块内存赋值后返回,那么就是真正的深拷贝。如果直接返回自身,那么它只是浅拷贝。
b. 用archiver方式:
NSArray* trueDeepCopyArray = [NSKeyedUnarchiverunarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
这是真正意义上的深拷贝,不依赖于实际类Copying协议的实现。
4. 用Category实现自定义的深拷贝deepmutableCopy,如:
- - (NSMutableArray *)mutableDeepCopy
- {
- NSMutableArray *ret = [[NSMutableArrayalloc] initWithCapacity:[self count]];
- for (id value in self)
- {
- id oneCopy = nil;
- if ([value respondsToSelector:@selector(mutableDeepCopy)])
- oneCopy = [value mutableDeepCopy];
- else if ([value respondsToSelector:@selector(mutableCopy)])
- oneCopy = [value mutableCopy];
- if (oneCopy == nil)
- oneCopy = [value copy];
- [ret addObject: oneCopy];
- }
- return ret;
- }