iOS中copy,mutableCopy到底什麼區別!深拷貝和淺拷貝的區別!

1、在字符串屬性中使用copy修飾符

先看段代碼,定義一個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修飾的字符串屬性(字符串屬性是可變字符串或不可變字符串都可)時,是作了淺拷貝的。

2、在數組屬性中使用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修飾的緣由。

其餘對象類型好比字典等等均可以以此類推。

3、使用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...

相關文章
相關標籤/搜索