捡起N久之前的知识整理一下
1.拷贝语法的目的
改变副本的时候,不会影响到源对象
深拷贝:内容拷贝,会产生新的对象。新对象计数器置为1,源对象计数器不变。
浅拷贝:指针拷贝,不会产生新的对象。源对象计数器+1。
2.深拷贝or浅拷贝
拷贝一个object也就是创建一个新的实例,并且初始化为拷贝源的值。对于像boolean,integer这类值,拷贝就是直接赋值。对于指针形的object就分为浅拷贝和深拷贝。浅拷贝是只创建一个新的指针,并指向同一块数据。深拷贝就是数据和指针都创建。
3.copy和retain的区别
retain不创建指针,不创建对象,只是引用计数+1。
copy创建指针,指针指向旧对象的区域。新对象引用计数为1,一定程度上减少了对旧对象的依赖。
非容器类对象的拷贝
NSString *str = @"helloWorld";
NSString *strCopy = [str copy];
NSLog(@"%p %p",str,strCopy);
//打印结果:0x100517068 0x100517068
NSMutableString *str = [[NSMutableString alloc]initWithString:@"helloWorld"];
NSString *strCopy = [str copy];
NSLog(@"%p %p",str,strCopy);
//打印结果:0x6080000786c0 0x6080000399e0
copy不可变对象:浅拷贝
copy可变对象:深拷贝,but!返回的是不可变对象
NSString *str = @"helloWorld";
NSMutableString *strMutCopy = [str mutableCopy];
[strMutCopy appendFormat:@"!!!"];
NSLog(@"%p %p %@",str,strMutCopy,strMutCopy);
//打印结果:0x100c25068 0x60000007a5c0 helloWorld!!!
NSMutableString *str = [[NSMutableString alloc]initWithString:@"helloWorld"];
NSMutableString *strMutCopy = [str mutableCopy];
[strMutCopy appendFormat:@"!!!"];
NSLog(@"%p %p %@",str,strMutCopy,strMutCopy);
//打印结果:0x600000264140 0x600000264180 helloWorld!!!
mutableCopy不可变对象or可变对象:都是深拷贝,返回的都是可变对象
对于非容器类对象:copy可变对象返回可变对象,copy不可变对象返回不可变对象,mutableCopy可变不可变都可以返回可变对象。
容器类对象的拷贝
NSArray *array = @[@"1",@"2",@"3"];
NSArray *arrayCopy = [array copy];
NSLog(@"%p %p",array,arrayCopy);
//打印结果:0x60000004f5a0 0x60000004f5a0
NSArray *array = @[@"1",@"2",@"3"];
NSMutableArray *arrayMutableCopy = [array mutableCopy];
[arrayMutableCopy addObject:@"4"];
[arrayMutableCopy replaceObjectAtIndex:0 withObject:@"first"];
NSLog(@"%p %p %@",array,arrayMutableCopy,arrayMutableCopy);
/**打印结果:0x600000054250 0x600000053e90 (
first,
2,
3,
4
)
*/
从以上结果来看,貌似只要对数组进行了mutableCopy,貌似数组和数组元素都深拷贝了......
然鹅......并不是酱紫,是因为我们对数组元素进行了replaceObjectAtIndex操作导致的地址重新创建了。其实,单纯的对数组进行mutableCopy,数组元素是浅拷贝的。于是,用以下代码进行了验证
NSArray *array = @[@"1",@"2",@"3"];
NSArray *arrayCopy = [array copy];
NSMutableArray *arrayMutableCopy = [array mutableCopy];
NSLog(@"%p %p %p",array[0],arrayCopy[0],arrayMutableCopy[0]);
//打印结果:0x10f2d5070 0x10f2d5070 0x10f2d5070
所以,如果对容器类对象进行深拷贝连同元素都是创建一个新的地址的话,就要进行如下操作了
NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"],@"2",@"3", nil];
NSArray *deepCopyArray = [[NSArray alloc]initWithArray:array copyItems:YES];
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
NSLog(@"%p %p %p",array[0],array[1],array[2]);
NSLog(@"%p %p %p",deepCopyArray[0],deepCopyArray[1],deepCopyArray[2]);
NSLog(@"%p %p %p",trueDeepCopyArray[0],trueDeepCopyArray[1],trueDeepCopyArray[2]);
/**打印结果:
0x608000073140 0x10991b080 0x10991b0a0
0xa000000000000311 0x10991b080 0x10991b0a0
0x608000073440 0xa000000000000321 0xa000000000000331
*/
对于容器类对象:
1.可以用“先归档再解归档”的方法实现容器类及其元素的深拷贝。是真正意义上的深拷贝。
2.initWithArray: copyItems:方法会对可变元素进行深拷贝,不可变元素进行浅拷贝。
自定义对象的拷贝
自定义对象实现拷贝,需要遵循<NSCopying><NSMutableCopying>协议,实现两个方法
- (id)copyWithZone:(NSZone *)zone //可变拷贝
- (id)mutableCopyWithZone:(NSZone *)zone //不可变拷贝
对象内部方法实现:
.h
@property(nonatomic,copy)NSString *name;
@property(nonatomic,strong)NSMutableString *variety;
@property(nonatomic,assign)NSInteger age;
.m
//重写init方法
-(instancetype)init
{
if (self = [super init]) {
self.name = @"doggie";
self.variety = [[NSMutableString alloc]initWithString:@"金毛"];
self.age = 3;
}
return self;
}
//遵循NSCopying协议才能实现此方法
-(id)copyWithZone:(NSZone *)zone
{
Dog *dog = [[self class]allocWithZone:zone];
dog.name = [_name copy];
dog.variety = [_variety copy];
//基本数据类型直接赋值
dog.age = _age;
return dog;
}
//遵循NSMutableCopying协议才能实现此方法
-(id)mutableCopyWithZone:(NSZone *)zone
{
Dog *dog = [[self class]allocWithZone:zone];
dog.name = [_name mutableCopy];
dog.variety = [_variety mutableCopy];
dog.age = _age;
return dog;
}
测试代码:
Dog *dog1 = [[Dog alloc]init];
Dog *dog2 = [dog1 copy];
Dog *dog3 = [dog1 mutableCopy];
NSLog(@"%p %p",dog1.variety,dog1.name);
NSLog(@"%p %p",dog2.variety,dog2.name);
NSLog(@"%p %p",dog3.variety,dog3.name);
/**输出结果:
0x7fdbba4a2910 0x107221098
0x7fdbba4a2910 0x107221098
0x7fdbba4a2ad0 0xa00656967676f646
*/
总结一下
1.copy返回的都是不可变对象
2.可变对象都是深拷贝
3.不可变对象copy是浅拷贝,mutableCopy是深拷贝
4.容器对象不用特殊的方法都是单层拷贝