iOS 淺拷貝與深拷貝解析

1、什么是淺拷貝,什么是深拷貝

淺拷貝表示的是不拷貝內容,只拷貝對應的指針,即拷貝之后的值指向內存中的地址是一樣的。深拷貝表示的是不拷貝指針,而拷貝的是內容,即拷貝之后的值是不變的,但是指向內存中的地址和拷貝前對應的值的內存中的地址是不一樣的,可以說是全新的一個地址。

2、一個多層的數組進行拷貝,只有一層進行了深拷貝,這種算深拷貝?

這種不能說是深拷貝,只能說是單層深拷貝。

3、copy和mutableCopy

在使用copy和mutableCopy進行相關處理時需要區分集合對象和非集合對象。
集合對象:指的是NSArray,NSDictionary之類的
非集合對象:NSString,NSNumber之類的

  • 非集合對象中的imutable和mutable,imutable指的就是不可變對象,例如NSString,mutable指的是可變對象NSMutableString
    NSString *string = [NSString stringWithFormat:@"source"];
    NSString *cString = [string copy];
    NSMutableString *mString = [string mutableCopy];
    NSLog(@"%p",string);//0xa00656372756f736
    NSLog(@"%p",cString);//0xa00656372756f736
    NSLog(@"%p",mString);//0x60c00024f180

    NSMutableString *mutableString = [NSMutableString stringWithFormat:@"source"];
    NSString *cString = [mutableString copy];
    NSString *mString = [mutableString mutableCopy];
    NSLog(@"%p",mutableString);//0x600000245f40
    NSLog(@"%p",cString);//0xa00656372756f736
    NSLog(@"%p",mString);//0x600000246060

從最后輸出的地址可以看出,在非集合對象中,當對象為imutable時,copy是淺拷貝,mutableCopy是深拷貝,當對象為mutable時,copy和mutableCopy都是深拷貝。還有一個很有意思需要注意的地方:執行下面代碼時會出現什么問題?

    NSMutableString *mString1 = [mutableString copy];
    [mString1 appendString:@"source"];

答案就是程序會crash,原因就是非集合類型中的mutable的對象使用copy返回的是imutable的值,雖然是深拷貝,但是類型變了,調用了不存在的方法,自然就會crash。

  • 集合對象
    也分imutable和mutable對象
    NSArray *array = @[@"1",@"2",@"3"];
    NSArray *cArray = [array copy];
    NSMutableArray *mArray = [array mutableCopy];
    NSLog(@"%p",array);//0x608000243930
    NSLog(@"%p",cArray);//0x608000243930
    NSLog(@"%p",mArray);//0x608000243cc0

    NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil];
    NSArray *cArray = [mutableArray copy];
    NSMutableArray *mArray = [mutableArray mutableCopy];
    NSLog(@"%p",mutableArray);//0x60000024ff60
    NSLog(@"%p",cArray);//0x600000250650
    NSLog(@"%p",mArray);//0x600000250530

從上面輸出的內存地址可以看出,不可變的集合對象使用copy是淺拷貝,使用mutableCopy是深拷貝。可變的集合對象使用copy和mutableCopy都是深拷貝。同樣的問題,如果

    NSMutableArray *mArray1 = [mutableArray copy];
    [mArray1 addObject:@"4"];

同樣是會導致crash。原因和上面所說的一樣。這也是為什么可變類型的對象不要使用copy進行修飾的原理。
最后結論 :不管是集合對象和非集合對象,其不可變對象,使用copy是淺拷貝,只會拷貝指針,而mutableCopy是深拷貝。對于可變對象,使用copy是深拷貝,但是深拷貝之后的值imutable類型的,不能使用mutable類型才有的方法。使用mutableCopy是深拷貝。 當一個NSArray實例用strong修飾而不是用copy修飾,那么NSArray的賦值是一個可變數組的時候,只是對可變對象進行了淺拷貝,當可變數組改變的時候,NSArray的實例也會發生改變,這會導致一些bug,如果用copy修飾,那么就會對可變數組進行深拷貝,得到一個新的不可變數組,自然不會因為可變數組的改變而導致當前數組的改變。

4、多層拷貝
    Company *c1 = [[Company alloc] init];
    c1.name = @"c1";
    c1.location = @"HK";
    
    Company *c2 = [[Company alloc] init];
    c2.name = @"c2";
    c2.location = @"USA";
    
    People *p1 = [[People alloc] init];
    p1.name = @"Jim";
    [p1.companyInfo addObject:c1];
    [p1.companyInfo addObject:c2];
    
    People *p2 = [[People alloc] init];
    p2.name = @"KX";
    [p2.companyInfo addObject:c1];
    [p2.companyInfo addObject:c2];
    
    NSMutableArray *data = [NSMutableArray arrayWithObjects:p1,p2, nil];
    NSLog(@"1:");
    int i =0;
    NSLog(@"data:%p",data);
    for (People *p in data) {
        if (i==0) {
            NSLog(@"p1");
        }else{
            NSLog(@"p2");
        }
        NSLog(@"%p",p);
        NSLog(@"%p",p.name);
        i++;
    }
    i = 0;
    NSLog(@"2:");
    NSArray *cArray = [data copy];
    NSLog(@"cArray:%p",cArray);
    for (People *p in cArray) {
        if (i==0) {
            NSLog(@"p1");
        }else{
            NSLog(@"p2");
        }
        NSLog(@"%p",p);
        NSLog(@"%p",p.name);
         i++;
    }
    NSLog(@"3:");
    i = 0;
    NSMutableArray *mArray = [data mutableCopy];
    NSLog(@"mArray:%p",mArray);
    for (People *p in mArray) {
        if (i==0) {
            NSLog(@"p1");
        }else{
            NSLog(@"p2");
        }
        NSLog(@"%p",p);
        NSLog(@"%p",p.name);
         i++;
    }

log:

1:
data:0x6040002528a0
p1
0x6040000368e0
0x1055ce118
p2
0x604000036940
0x1055ce138
2:
cArray:0x60c0000339e0
p1
0x6040000368e0
0x1055ce118
p2
0x604000036940
0x1055ce138
3:
mArray:0x600000054880
p1
0x6040000368e0
0x1055ce118
p2
0x604000036940
0x1055ce138

從輸出的地址可以看出,雖然copy和mutableCopy輸出的地址都是不一樣的,也屬于深拷貝,但是里面的對象的地址都是一樣的,這說明這樣拷貝只是上面所說的單層深拷貝。而不是完整深拷貝。
解決方案:
新建一個數組,然后把數組中的數據取出來進行拷貝,再把數據放進新數組中。這樣就能實現數組中的數據深拷貝。
//未完待續,還有NSCopying和NSMutableCopying以及實現copywithZone的注意點。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容