前段时间突然被问到copy关键字的作用以及产生的效果,现在就来讨论讨论。
首先阐述两个概念:
深复制:就是说复制时除了指针本身,对象内容也被复制了一份
浅复制:就是说只是复制了指针本身,对象内容并没有被复制
一.集合对象的复制
以数组类型为例,假设现在有一个数组:
NSArray *array =[NSArray arrayWithObjects:[Person new],[Person new],[Person new],[Person new], nil];
这个数组本身是不可变的,所以在调用copy方法时,就会是浅复制。
调用mutableCopy时,则是深复制,会生成一个新的可变数组,但是数组内部Person对象并没有被复制。
如若是一个可变数组:
NSMutableArray *mutableArray =[NSMutableArray arrayWithObjects:[Person new],[Person new],[Person new],[Person new], nil];
这个数组在调用copy和mutableCopy的效果是一样的,都是深复制,但是copy方法得到的是新的不可变数组对象,而mutableCopy方法得到的是新的可变数组对象。同上数组内部Person对象并没有被复制。
那么集合类型怎么做到内部对象也深复制呢?敲黑板划重点来了:
如若想要集合内部对象深复制就要使用系统API:
- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;
使用的时候flag必须传YES,如果flag传的是NO,那么集合内部对象还是浅复制,但是虽说flag传YES是深复制,也只能复制第一层元素对象,也就是说如果是双重数组NSArray<NSArray<Person *> *> *类型的复制,那个Person对象还是不会被复制的。
并且,如果集合内部对象需要深复制,Person对象必须实现NSCoping协议,并实现copyWithZone:方法,否则这个方法会抛异常。
结论:
数组类型/复制类型 | copy | mutableCopy |
NSArray | 浅复制 | 深复制 |
NSMutableArray | 深复制 | 深复制 |
二.自定义对象类型的复制
这个复制的话就得小心了,在使用之前必须要先实现NSCoping协议或NSMutableCoping协议,否则会因为未实现copyWithZone:或者mutableCopyWithZone:方法而抛异常。
这个是否深复制就看方法内部如何实现的了,一般而言都是需要深复制的,不然copy就失去了它的意义。
举个例子:
@interface Person : NSObject<NSCopying, NSMutableCopying>
@property(nonatomic, assign)NSInteger age;
@end
@implementation Person
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
Person *p = [[Person allocWithZone:zone] init];
p.age = self.age;
return self;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
Person *p = [[Person allocWithZone:zone] init];
p.age = self.age;
return self;
}
@end
这样的内部实现就是会深复制的了。