先看段代码,定义一个Person类,包含以下属性segmentfault
@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
0xfeb2675144eac410app
可见在把可变字符串赋值给带copy修饰的字符串属性时,是作了深度拷贝的。把Person中的name定义为NSMutableString的对象结果是同样的。
若是把str定义为不可变对象NSString。则输出结果以下,说明把不可变字符串赋值给带copy修饰的字符串属性时,只作了浅拷贝。把Person中的name定义为NSMutableString的对象结果是同样的。atom
输出结果:
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
0x10bc572b0code
结论:
把可变字符串赋值给带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
)
(get
Tom, Jone, Jack
)
2019-07-17 01:34:44.020984+0800 qqq[15795:4361304]
0x600002c908d0
0x600002ccb060it
可见在把可变数组赋值给带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修饰的缘由。
其余对象类型好比字典等等均可以以此类推。
先看看下面这段代码:
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和深拷贝浅拷贝没有关系。
能够参考这篇文章