先看段代碼,定義一個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和深拷貝淺拷貝沒有關係。
能夠參考這篇文章