1、要了解浅拷贝与深拷贝,首要的是理解浅拷贝是什么,深拷贝是什么。
<1>浅拷贝:就相当于retain,只copy了一个对象的引用,和本身是同一个对象,就相当于影子。
<2>深拷贝:从新开辟了一块内存空间,用来存放原来对象里面的东西,这个时候,copy出来的对象和原来的对象不是同一个对象,他们的内容一样,就相当于克隆人。
<3>拷贝出来的的对象是什么类型取决于使用什么拷贝。
2、拷贝的用法
<1>不可变copy拷贝不可变对象(浅拷贝):
NSArray *array=[[NSArray alloc]initWithObjects:@"1",@"2", nil]; NSArray *array1=[array copy]; NSLog(@"array1=%@",array1); NSLog(@"array=%p,array1=%p",array,array1); NSLog(@"array = %lu ,array1 = %lu",[array retainCount],[array1 retainCount]);
其输出结果:
看输出结果反馈出:对不可变数组array进行不可变copy时,拷贝出来的array1是跟array一样的对象且两个数组的引用计数都+1,相当于对array本身的一个引用而已。
<2>不可变copy拷贝可变对象(深拷贝):
NSMutableArray *mArray=[[NSMutableArray alloc]initWithObjects:@"1",@"2", nil]; NSArray *array=[mArray copy]; NSLog(@"mArray=%p,array=%p",mArray,array); NSLog(@"array=%@",array); NSLog(@"array的类型%@",[array class]); NSLog(@"mArray = %lu ,array = %lu",[mArray retainCount],[array retainCount]);
其输出结果:
看输出结果反馈出:对可变数组mArray进行不可变copy操作,拷贝出来的array数组与mArray数组的内存地址是不一样的且两块内存地址内容是相同的,而内容是一样的且引用计数不发生改变,array数组的类型不变依旧是不可变数组。由此可以得出不可变copy拷贝可变对象是深拷贝。
<3>可变copy拷贝不可变对象(深拷贝):
NSArray *array=[[NSArray alloc]initWithObjects:@"1",@"2", nil]; NSMutableArray *mArray=[array mutableCopy]; NSLog(@"-%@",[[array mutableCopy] class]); NSLog(@"array=%p,mArray=%p",array,mArray); NSLog(@"mArray=%@",mArray); NSLog(@"mArray = %lu ,array = %lu",[mArray retainCount],[array retainCount]);
其输出结果:
看输出结果反馈出:对不可变数组array进行可变可变copy操作,拷贝出来的mArray数组与array数组的内存地址不同且两块内存地址内容是相同的,且拷贝出来的对象是可变的,引用计数并没有发生改变,由此可以得出可变copy拷贝不可变对象是深拷贝。
<4>可变copy拷贝可变对象(深拷贝):
NSMutableArray *mArray=[[NSMutableArray alloc]initWithObjects:@"1",@"2", nil]; NSMutableArray *array=[mArray mutableCopy]; NSLog(@"%@",[[mArray mutableCopy] class]); NSLog(@"mArray=%p,array=%p",mArray,array); NSLog(@"array=%@",array); NSLog(@"mArray = %lu ,array = %lu",[mArray retainCount],[array retainCount]);
其输出结果:
看输出结果反馈出:对可变数组array进行可变可变copy操作,拷贝出来的array数组与mArray数组的内存地址不同且两块内存地址内容是相同的,且拷贝出来的对象是可变的,没有引起引用计数的变化,由此可以得出可变copy拷贝可变对象是深拷贝。
<5>自定义类的copy:
自定义一个person类
.h文件
#import <Foundation/Foundation.h> //要实现copy必须遵守NSCopying或者NSMutableCopying协议,这里面有一个必须实现的协议copyWithZone: @interface Person : NSObject<NSCopying> @property(retain,nonatomic)NSString *name; @property(copy,nonatomic)NSArray *array; @property(copy,nonatomic)NSMutableArray *mArray; @end
.m文件
#import "Person.h" @implementation Person -(id)copyWithZone:(NSZone *)zone { Person *pp=[[Person alloc]init]; // NSLog(@"pp=%p",pp); pp.name=self.name; return pp; } @end
在main.m文件中,导入person类头文件且添加下列代码
/* 要实现copy必须遵守NSCopying或者NSMutableCopying协议,这里面有一个必须实现的协议copyWithZone: */ Person *p=[[Person alloc]init]; p.name=@"张三"; Person *p1=[p copy]; NSLog(@"p=%p,p1=%p",p,p1); NSLog(@"p1的名字为%@",p1.name);
运行结果得到:
可以得出:自定义对象进行copy操作得到的是两块补一样的内存地址,且内容是一样的。
<6>属性的copy:
1、copy修饰不可变属性的时候,就相当于retain
2、copy修饰可变属性的时候,相当于不可变copy拷贝可变对象。属于深拷贝,这个时候,属性和对属性赋值的对象的内存都需要单独管理
3、建议对象类型都是用retain