对象复制,顾名思义就是将一个已有的对象复制一份出来,开辟一个新的内存来储存对象,相当于一个副本;对象复制又分为浅拷贝和深拷贝;这里我们就来简单的介绍下对象复制。
Foundation框架张支持复制的对象有NString、NSArra、NSNumber、NSDictionar、NSMutableString、NSMutablerArray、NSMutableDictionary等。我们可以自定义对象来支持复制,一个前提条件就会必须实现NSCopying协议或者NSMutableCopying协议或者两者都实现。
首先我们先来区分下copy、retain,先举个例子,可能会更清晰很多;
];
NSMutableArray *array1 = [array retain];
[array1 removeLastObject];
for(NSObject* obj in array)
{
}
NSArry *array2 = @[@"one", @"two", @"three", @"four" ];
NSMutableArray *array3 = [array copy];
[array3 removeLastObject];
for(NSObject* obj in array2)
{
}
这样打印出来的结果是,第一次打印的时候只打印出3个元素,第二次打印的时候打印出4个元素。
retain、copy总结:
retain只是引用计数加1,两个指针指同一个内存,也就是array和array1共享一块内存;
copy是开辟出一个内存,两个指针指向两块内存,array2、array3都拥有自己的内存;
复制对象的种类:
copy:产生对象的副本是不可变的
mutableCopy:产生的对象副本是可变的
可变与不可变的区别就是是否可以对对象内容进行增删改,比如NSMutableArray与NSArray,我们可以为NSMutableArray增加元素、删除元素、修改元素等操作,而对于NSArray对象就不可以。
同样我们举个例子来区分下copy与mutablecopy:
NSArray *array = [[NSArray alloc] initWithObject:@"one", @"two", @"three",nil];
NSArray *array1 = [array copy];
NSMutableArray * array2 = [array muttablecopy];
[array1 addObject:@"five"]; //程序执行到这里报错
[array2 addObject:@"four"];
很明显,copy和mutablecopy返回的对象不同,copy返回的是不可变的,mutablecopy返回的是可变的。
可能有些人会问,array1我用NSMutableArray来定义不就可以么,他也不报错。但是结果不是你想的那样的,可能你觉得这样可行,但copy就要跟你过不去了。copy返回的指针是不可变的对象,如果你用NSMutableArray来定义array1,即NSmutableArray array1 = [array copy];用copy来复制对象,他返回的对象只能交给不可变的对象,你这样把他强扭过来,他还是不可变的。就像一块橡皮泥,你怎么捏各种形状出来,他还是一个橡皮泥,不可能变为一个蛋糕或者饼干。你想要返回一个可变对象,就只能使用mutablecopy。
这里就是copy和mutablecopy的区别。
复制对象里面还有一个很重要的东西就是深拷贝和浅拷贝。
深拷贝:除了拷贝对象本身之外,对象里面所包含的属性或者对象都一起拷贝
浅拷贝:只拷贝对象本身,对象里面所包含的属性或者对象不进行拷贝。
foundation框架中支持复制的对象都是默认浅拷贝,不对对象里面的属性和对象进行拷贝。
同样,我们先举一个foundation框架中的对象来证明下它默认的是浅拷贝:
NSMutableArray *array = [[NSArray alloc] init];
for(int i=0; i<3;i++) {
NSObject *obj = [[NSObject alloc] init];
[array addObject:obj];
[obj release];
}
for(NSObject *obj in array){
NSLog(@" 复制之前:%d", obj.retainCount);
}
NSArray *array1 = [array copy];
for(NSObject *obj in array){
NSLog(@" 复制之后:%d", obj.retainCount);
}
程序运行之后,我们可以看出数组array在复制之前和复制之后元素的引用计数都一样,所以我们可以证明foundation框架里面的对象默认是浅拷贝的。
我们来自定义一个对象,来理解下深拷贝:
@proper(nontomic, retain) NString *name;
@proper(nontomic, retain) NSNumber *age;
@end
@implement Person
{
-(id)copywithzone:(NSZone*)zone {
Person *person = [[[self class] allocwithzone:zone] init];
person.name = [_name copy];
person.age = [_age copy];
return person;
}
}
@end
main.m
-autoreleasepool
{
Person *person = [[Person alloc] init];
Person *person1 = [person copy];
NSLog(@"%d", person.name.retainCount);
}
程序执行后,发现复制前name的引用计数是1,复制后是2,对属性name进行了复制,这就是深拷贝。