转自“红黑联盟”,网址:http://www.2cto.com/kf/201405/302273.html
第一、复制对象的基本概念
复制一个对象为副本,开辟一块新的内存来存储副本对象。
第二、如果一个对象想具备复制的功能,必须实现协议和协议
NSObject自带的常用的对象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableArray、NSMutableDictionay、NSMutableString,copy产生的对象时不可变的,mutableCopy产生的对象时可变的
第三、retain和copy的区别
@autoreleasepool { NSMutableArray *array=[NSMutableArray arrayWithObjects:@"one",@"two",@"three",@"four",nil]; NSMutableArray *retainArray=[array retain]; [retainArray removeLastObject]; for(NSString *str in array) { NSLog(@"the part is %@",str); } NSLog(@"the retaincount is %ld",[retainArray retainCount]); // insert code here... NSLog(@"Hello, World!"); }
结果:
2014-05-19 10:58:22.639 objective[1095:303] the part is one 2014-05-19 10:58:22.641 objective[1095:303] the part is two 2014-05-19 10:58:22.641 objective[1095:303] the part is three 2014-05-19 10:58:22.641 objective[1095:303] the retaincount is 2
NSMutableArray *array=[NSMutableArray arrayWithObjects:@"one",@"two",@"three",@"four",nil]; NSMutableArray *retainArray=[array mutableCopy]; [retainArray removeLastObject]; for(NSString *str in array) { NSLog(@"the part is %@",str); } NSLog(@"the retaincount is %ld",[retainArray retainCount]);
结果
2014-05-19 10:59:03.826 objective[1104:303] the part is one
2014-05-19 10:59:03.828 objective[1104:303] the part is two
2014-05-19 10:59:03.828 objective[1104:303] the part is three
2014-05-19 10:59:03.829 objective[1104:303] the part is four
2014-05-19 10:59:03.829 objective[1104:303] the retaincount is 1
第四、COPY和MutableCopy的区别
COPY 返回一个不可变对象的副本,MutalbeCopy返回一个可变对象的副本。
NSArray *array=[NSArray arrayWithObjects:@"one",@"two", nil]; NSMutableArray *array1=[array copy]; [array1 addObject:@"three"]; //error NSMutableArray *array2=[array mutableCopy]; [array2 addObject:@"three"]; //right // insert code here... NSLog(@"Hello, World!");
第五、浅copy和深copy
浅复制尽复制对象本身,对象里的属性、包含的对象不做复制
深复制复制全部,包括对象的属性和其他对象
Foundation框架支持复制的类,默认是浅复制
NSMutableArray *array=[[NSMutableArray alloc] init]; for(int i=0;i<3;i++) { NSObject *obj=[[NSObject alloc] init]; [array addObject:obj]; [obj release]; } for(NSObject *obj1 in array) { NSLog(@"地址为 %p,引用计数是 %ld",obj1,obj1.retainCount); } NSMutableArray *array2=[array copy]; for(NSObject *obj2 in array2) { NSLog(@"地址为 %p,引用计数是 %ld",obj2,obj2.retainCount); }
2013-09-30 17:28:01.492 FDAS[681:303] 地址为 0x1001081f0,引用计数是 1 2013-09-30 17:28:01.506 FDAS[681:303] 地址为 0x100108230,引用计数是 1 2013-09-30 17:28:01.506 FDAS[681:303] 地址为 0x100108240,引用计数是 1 2013-09-30 17:28:01.507 FDAS[681:303] 地址为 0x1001081f0,引用计数是 2 2013-09-30 17:28:01.507 FDAS[681:303] 地址为 0x100108230,引用计数是 2 2013-09-30 17:28:01.507 FDAS[681:303] 地址为 0x100108240,引用计数是 2
第五、对象的自定义拷贝
对象拥有复制特性,必须实现NSCopying,NSMutableCopying协议,实现该协议的copyWithZone方法和mutableCopyWithZone方法
深拷贝和浅拷贝的区别就在于copyWithZone方法的实现,
浅拷贝代码如下:
#import @interface Person : NSObject @property(nonatomic,retain)NSString *name; @property(nonatomic,retain)NSString *age; @end
#import "Person.h" @implementation Person - (id)copyWithZone:(NSZone *)zone { //实现自定义浅拷贝 Person *person=[[self class] allocWithZone:zone]; person.age=_age; person.name=_name; return person; } @end
main函数为:
@autoreleasepool { Person *person=[[Person alloc] init]; [email protected]"andy"; [email protected]"20"; Person *person2=[person copy]; NSLog(@"person 地址为%p,person2地址为%p",person.name,person2.name); }
输出结果为:
2013-09-30 17:48:41.007 FDAS[732:303] person 地址为0x1000022c8,person2地址为0x1000022c8
深拷贝代码如下:
- (id)copyWithZone:(NSZone *)zone { //实现自定义浅拷贝 Person *person=[[self class] allocWithZone:zone]; person.age=[_age copy]; person.name=[_age copy]; return person; }
结果:
2013-09-30 17:55:13.603 FDAS[742:303] person 地址为0x1000022c8,person2地址为0x1000022e8
NSArray *arr=[NSArray arrayWithObjects:@"one",@"two",nil]; NSArray *arr2=[arr copy]; NSLog(@"the dress of arr is %p the dress of arr2 is %p",arr,arr2); NSLog(@"the retainCount is %ld",arr.retainCount);
执行结果为:
2013-09-30 18:01:01.394 FDAS[787:303] the dress of arr is 0x100108320 the dress of arr2 is 0x100108320
2013-09-30 18:01:01.396 FDAS[787:303] the retainCount is 2
结果是一样的,是因为Foundation对于不可变复制对象而言,copy方法做了优化,相当于retain,故retaincount变成2.
相当于 在copyWithZone方法中:return [self retain];
第六、copy、mutableCopy和retain之间的关系
在Foundation对象中,copy是一个不可变的对象时,作用相当于retain
当使用mutableCopy时,不管源对象是否可变,副本是可变的,并且实现真正意义上的copy
当我们使用copy一个可变对象时,副本对象是不可变的。
关于深拷贝和浅拷贝:
第一、浅拷贝:
Car *car=[[[self class] allocWithZone:zone] init]; car.engine=_engine; car.name=_name; car.weight=_weight; return car;
测试代码:
Car *car = [[Car alloc] init]; Engine *engine = [[Engine alloc] init]; car.engine = engine; [engine release]; //NSLog(@"engine retaincount is %lu",[engine retainCount]); car.name = @"奥迪"; car.weight = @1000; Car *car2=[car copy]; // NSLog(@"car2 retaincount is %lu",[car2 retainCount]); NSLog(@"car %@,car2:%@",car.engine,car2.engine);
输出结果:
car ,car2:
可以看出浅复制只是复制指针,并没有创建新的内存空间
第二、深拷贝:
- (id)copyWithZone:(NSZone *)zone { /***浅拷贝**/ Car *car=[[[self class] allocWithZone:zone] init]; Engine *engineCopy=[[_engine copy] autorelease]; car.engine=engineCopy; NSString *namecopy=[[_name copy] autorelease]; car.name=namecopy; NSNumber *weightcopy=[[_weight copy] autorelease]; car.weight=weightcopy; return car; }
测试代码:
Car *car = [[Car alloc] init]; Engine *engine = [[Engine alloc] init]; car.engine = engine; [engine release]; //NSLog(@"engine retaincount is %lu",[engine retainCount]); car.name = @"奥迪"; car.weight = @1000; Car *car2=[car copy]; // NSLog(@"car2 retaincount is %lu",[car2 retainCount]); NSLog(@"car %@,car2:%@",car.engine,car2.engine);
结果:
car ,car2:
开辟了新的空间,zone代表一块内存空间
Car *car=[[[self class] allocWithZone:zone] init];
注意上述代码用的是【self class】,而不是car,因为如果是用car,那么car的子类在调用此方法去实现copy协议时,就会出现内存问题
另外,当子类继承了父类时,他继承了父类的一切属性,包括要实现的协议
第三、NSFoundation,当我们copy的时一个不可变对象时,默认的copy都是浅拷贝,相当于retain
NSArray *array =[NSArray arrayWithObjects:@"one",@"two",@"three", nil]; NSArray *array1 = [array copy]; NSLog(@"%p",array); NSLog(@"%p",array1); NSLog(@"the retaincount is %lu",[array retainCount]);
输出结果:
copyDemo1[673:303] 0x10010a5d0
2013-12-28 20:01:10.969 copyDemo1[673:303] 0x10010a5d0
2013-12-28 20:01:10.969 copyDemo1[673:303] the retaincount is 2
注意retaincount会增加
当使用mutableCopy时,不管对象是否可变,都会实现深拷贝
NSArray *array =[NSArray arrayWithObjects:@"one",@"two",@"three", nil]; NSMutableArray *array1 = [array mutableCopy]; NSLog(@"%p",array); NSLog(@"%p",array1); NSLog(@"the retaincount is %lu",[array retainCount]);
结果:
copyDemo1[695:303] 0x10010a5d0
2013-12-28 20:07:08.570 copyDemo1[695:303] 0x10010b260
2013-12-28 20:07:08.570 copyDemo1[695:303] the retaincount is 1
第四、retain相当于两个对象指向同一个指针
NSMutableArray *array1 = [[NSMutableArray alloc] initWithObjects:@"one",@"two",@"three",@"foure", nil]; NSMutableArray *array2 = [array1 retain]; [array2 removeLastObject]; NSLog(@"%@",array1); NSLog(@"the retaincount is %ld",array2.retainCount);
结果:
2013-12-28 20:13:02.915 copyDemo1[736:303] ( one, two, three ) 2013-12-28 20:13:02.917 copyDemo1[736:303] the retaincount is 2