美文网首页
copy和mutableCopy

copy和mutableCopy

作者: GemShi | 来源:发表于2017-03-06 23:11 被阅读10次

捡起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
*/
copy和mutableCopy copy和mutableCopy copy和mutableCopy

总结一下
1.copy返回的都是不可变对象
2.可变对象都是深拷贝
3.不可变对象copy是浅拷贝,mutableCopy是深拷贝
4.容器对象不用特殊的方法都是单层拷贝

相关文章

网友评论

      本文标题:copy和mutableCopy

      本文链接:https://www.haomeiwen.com/subject/djxpgttx.html