iOS中copy,mutableCopy到底什么区别!深拷贝和浅拷贝的区别!

一、在字符串属性中使用copy修饰符

先看段代码,定义一个Person类,包含如下属性

@property (nonatomic,copy) NSString *name;

在一个ViewController的viewDidLoad使用这个类。如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSMutableString *str = [[NSMutableString alloc] initWithString:@"iPhone"];
    Person *person = [[Person alloc]init];
    person.name = str;
    [str appendString:@"6"];
    NSLog(@"\n%@\n%@", str, person.name);
    NSLog(@"\n%p\n%p", str, person.name);
}

输出结果如下:
2019-07-17 00:43:41.627519+0800 qqq[14328:4332153]
iPhone6
iPhone
2019-07-17 00:43:41.627729+0800 qqq[14328:4332153]
0x600003861ad0
0xfeb2675144eac410

可见在把可变字符串赋值给带copy修饰的字符串属性时,是做了深度拷贝的。把Person中的name定义为NSMutableString的对象结果是一样的。
如果把str定义为不可变对象NSString。则输出结果如下,说明把不可变字符串赋值给带copy修饰的字符串属性时,只做了浅拷贝。把Person中的name定义为NSMutableString的对象结果是一样的。

输出结果:
2019-07-17 01:03:02.364902+0800 qqq[14916:4344263]
iPhone
iPhone
2019-07-17 01:03:02.365073+0800 qqq[14916:4344263]
0x10bc572b0
0x10bc572b0

结论:

把可变字符串赋值给带copy修饰的字符串属性(字符串属性是可变字符串或不可变字符串均可)时,是做了深度拷贝的。

把不可变字符串赋值给带copy修饰的字符串属性(字符串属性是可变字符串或不可变字符串均可)时,是做了浅拷贝的。

二、在数组属性中使用copy修饰符

在Person类中增加一个数组属性,代表其朋友数组。

@property (nonatomic,copy) NSArray * friends;

在viewDidLoad中添加如下代码,之前的可以先注释掉。

    NSMutableArray * arr = [[NSMutableArray alloc] initWithObjects:@"Tom",@"Jone",@"Jack",nil];
    Person *person = [[Person alloc]init];
    person.friends = arr;
    [arr addObject:@"Ben"];
    NSLog(@"\n%@\n%@", arr, person.friends);
    NSLog(@"\n%p\n%p", arr, person.friends);

输出结果如下:
2019-07-17 01:34:44.020709+0800 qqq[15795:4361304]
(

Tom,
Jone,
Jack,
Ben

)
(

Tom,
Jone,
Jack

)
2019-07-17 01:34:44.020984+0800 qqq[15795:4361304]
0x600002c908d0
0x600002ccb060

可见在把可变数组赋值给带copy修饰的NSArray属性时,是做了深度拷贝的。赋值给带copy修饰的NSMutableArray也是一样。
如果把arr定义为不可变数组NSArray。则输出结果如下,说明把不可变数组赋值给带copy修饰的数组属性时,只做了浅拷贝。把Person中的friends定义为NSMutableArray的对象结果是一样的。

2019-07-17 01:44:30.090481+0800 qqq[16110:4368368]
(

Tom,
Jone,
Jack

)
(

Tom,
Jone,
Jack

)
2019-07-17 01:44:30.090662+0800 qqq[16110:4368368]
0x600000558870
0x600000558870

结论和上面的一致

更近一步:如果Person的name属性是copy修饰的NSMutableString类型,给其赋值一个NSMutableString的对象,此时这个name依然是NSString类型。如果调用appendString程序就会崩溃。原因在于NSMutableString是继承自NSString,但是并没有重写针对可变类型的copy方法,copy方法依然返回不可变类型。这个时候调用NSMutableString的特有方法依然会失败。造成了定义的是可变类型,但是不能调用可变类型的方法的局面。这也是为什么可变类型不用copy修饰的原因。

其他对象类型比如字典等等都可以以此类推。

三、使用copy,和mutableCopy拷贝数组对象。

先看看下面这段代码:

    NSString * str1 = @"aaa";
    NSString * str2 = @"bbb";
    NSString * str3 = @"ccc";
    
    NSLog(@"str1=%@ address=%p \n",str1,str1);
    NSLog(@"str2=%@ address=%p \n",str2,str2);
    NSLog(@"str3=%@ address=%p \n",str3,str3);
    
    NSArray * array = [NSArray arrayWithObjects:str1,str2,str3, nil];
    //NSMutableArray * array = [NSMutableArray arrayWithObjects:str1,str2,str3, nil];
    

    NSArray * array2 = array;
    NSArray * array3 = [array copy];
    NSMutableArray * array4 = [array copy];
    NSMutableArray * array5 = [array mutableCopy];

    
    NSLog(@"array1:%p:%p-%p-%p ",array,array[0],array[1],array[2]);
    NSLog(@"array2:%p:%p-%p-%p ",array2,array2[0],array2[1],array2[2]);
    NSLog(@"array3:%p:%p-%p-%p ",array3,array3[0],array3[1],array3[2]);
    NSLog(@"array4:%p:%p-%p-%p ",array4,array4[0],array4[1],array4[2]);
    NSLog(@"array5:%p:%p-%p-%p ",array5,array5[0],array5[1],array5[2]);

这段代码的输出为:

str1=aaa address=0x10bc70068
str2=bbb address=0x10bc70088
str3=ccc address=0x10bc700a8
array1:0x6000039890e0:0x10bc70068-0x10bc70088-0x10bc700a8
array2:0x6000039890e0:0x10bc70068-0x10bc70088-0x10bc700a8
array3:0x6000039890e0:0x10bc70068-0x10bc70088-0x10bc700a8
array4:0x6000039890e0:0x10bc70068-0x10bc70088-0x10bc700a8
array5:0x600003989920:0x10bc70068-0x10bc70088-0x10bc700a8

注释掉生成array的代码,打开它下面的代码,生成mutable array的代码,则输出如下:

str1=aaa address=0x10b003068
str2=bbb address=0x10b003088
str3=ccc address=0x10b0030a8
array1:0x6000004013b0:0x10b003068-0x10b003088-0x10b0030a8
array2:0x6000004013b0:0x10b003068-0x10b003088-0x10b0030a8
array3:0x6000004025b0:0x10b003068-0x10b003088-0x10b0030a8
array4:0x600000402580:0x10b003068-0x10b003088-0x10b0030a8
array5:0x600000401a40:0x10b003068-0x10b003088-0x10b0030a8

结论:

不可变的NSArray在copy时是浅拷贝,mutableCopy是深拷贝
可变的NSMutableArray在copy时是深拷贝,在mutableCopy当然也是深拷贝

上面只是NSArray,NSMutableArray对copy和mutableCopy的实现。更一般的表述应该是,copy或mutableCopy本质上是调用如下方法
-(id)copyWithZone:(nullable NSZone *)zone
-(id)mutableCopyWithZone:(nullable NSZone *)zone
其内部实现表明了是深拷贝还是浅拷贝。所以copy或者mutableCopy和深拷贝浅拷贝没有关系。
可以参考这篇文章

https://segmentfault.com/a/11…

    原文作者:大鱼
    原文地址: https://segmentfault.com/a/1190000019785227
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞