对象复制,顾名思义就是将一个已有的对象复制一份出来,开辟一个新的内存来储存对象,相当于一个副本;对象复制又分为浅拷贝和深拷贝;这里我们就来简单的介绍下对象复制。

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进行了复制,这就是深拷贝。