一、在字符串属性中使用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和深拷贝浅拷贝没有关系。
可以参考这篇文章