iOS 關(guān)于深拷貝和淺拷貝的誤解

在iOS開(kāi)發(fā)中深拷貝和淺拷貝是一個(gè)被大家說(shuō)爛的話題了疯特,但是今天還是要拿出來(lái)說(shuō)一說(shuō)淹办。原因是印荔,前段時(shí)間在微信朋友圈看到一個(gè)朋友發(fā)的關(guān)于深拷貝和淺拷貝的總結(jié)攻询,當(dāng)時(shí)看了一眼从撼,我想他對(duì)深拷貝和淺拷貝沒(méi)有理解,而且被網(wǎng)上很多關(guān)于這方面的技術(shù)博客誤導(dǎo)了钧栖,我搜索了一下低零,發(fā)現(xiàn)網(wǎng)上很多的博客跟他下面總結(jié)的一樣。而且他去面試時(shí)拯杠,很多面試官也是這么理解深拷貝和淺拷貝的掏婶。
他的總結(jié)如下圖,大家可以看看潭陪,想想自己是否也是這么理解深拷貝和淺拷貝的:


copy_00.JPG

下面讓我們先來(lái)看幾個(gè)個(gè)例子雄妥,如果你認(rèn)可上圖的總結(jié)最蕾,那么看完下面的例子之后,請(qǐng)先想好結(jié)果老厌,然后再對(duì)照答案瘟则,看看自己的結(jié)果是否正確。

1. NSMutableArray對(duì)象的拷貝

我們先來(lái)看看對(duì)可變數(shù)組NSMutableArray對(duì)象進(jìn)行拷貝的例子:

        //1.創(chuàng)建四個(gè)可變字符串
        NSMutableString *av_0 = [NSMutableString stringWithString:@"Harry"];
        NSMutableString *av_1 = [NSMutableString stringWithString:@"Jamie"];
        NSMutableString *av_2 = [NSMutableString stringWithString:@"Micheal"];
        NSMutableString *av_3 = [NSMutableString stringWithString:@"Susan"];
        
        //2.創(chuàng)建一個(gè)可變數(shù)組枝秤,用來(lái)存放上面四個(gè)可變的字符串
        NSMutableArray *array_0 = [NSMutableArray arrayWithObjects:av_0,av_1, nil];
        
        //3.我們調(diào)用方法 mutableCopy 和 copy 來(lái)拷貝數(shù)組 array_0
        NSMutableArray *array_1 = [array_0 mutableCopy];
        NSArray *array_2 = [array_0 copy];
        
        
        //4. 修改可變字符串 av_0
        [av_0 appendString:@" Muhammed"];
  
        
        //5. 最后我們輸出 array_0,array_1,array_2 中的元素醋拧,請(qǐng)先思考結(jié)果如何是什么
        NSLog(@"array_0 = %@ \n array_1 = %@\n array_2 = %@",array_0,array_1,array_2);
    

首先我們先按照?qǐng)Dcopy_00.JPG中關(guān)于NSMutableArray的總結(jié)來(lái)分析下結(jié)果,根據(jù)上圖我們無(wú)論對(duì)NSMutableArray調(diào)用mutableCopy淀弹,還是copy方法丹壕,都是深拷貝。因此垦页,當(dāng)我們對(duì)數(shù)組array_0調(diào)用拷貝方法之后雀费,同時(shí)也會(huì)對(duì)其中的兩個(gè)元素av_0av_1進(jìn)行拷貝。那么當(dāng)我們改變av_0之后痊焊,對(duì)數(shù)組array_1array_2中的元素av_0應(yīng)該是沒(méi)有影響的,array_1array_2的輸出仍然是Harry忿峻。但是實(shí)際結(jié)果真的如此嗎薄啥?讓我們看看最后的輸出結(jié)果:

array_0 = (
    "Harry Muhammed",
    Jamie
) 
 array_1 = (
    "Harry Muhammed",
    Jamie
)
 array_2 = (
    "Harry Muhammed",
    Jamie
)

接著我們?cè)傧驍?shù)組array_0array_1中分別添加一個(gè)元素"av_2",av_3逛尚÷⒕澹看看三個(gè)數(shù)組array_0array_1绰寞,array_2中的元素個(gè)數(shù)是如何變化的到逊,它們之間是否會(huì)彼此影響:

        [array_0 addObject:av_2];
        [array_1 addObject:av_3];
        
        //請(qǐng)思考 array_0,array_1,array_2 的輸出是什么?
        NSLog(@"array_0 = %@ \n array_1 = %@\n array_2 = %@",array_0,array_1,array_2);

其輸出結(jié)果如下:

array_0 = (
    "Harry Muhammed",
    Jamie,
    Micheal
) 
 array_1 = (
    "Harry Muhammed",
    Jamie,
    Susan
)
 array_2 = (
    "Harry Muhammed",
    Jamie
)

由上面的結(jié)果我們可以看出滤钱,當(dāng)我們向可變數(shù)組array_0array_1中添加元素后觉壶,對(duì)數(shù)組array_02中的元素個(gè)數(shù)并沒(méi)有影響,并且array_0array_1也沒(méi)彼此影響件缸。

         //創(chuàng)建一個(gè)不可變數(shù)組 array_3
        NSArray *array_3 = @[av_2,av_3];
        
        //拷貝數(shù)組 array_3 分別賦值給 array_4铜靶,array_5
        NSMutableArray *array_4 = [array_3 mutableCopy];
        NSArray *array_5 = [array_3 copy];

        //修改數(shù)組 array_3 中的元素 av_2
        [av_2 appendString:@" Jackson"];

        //請(qǐng)思考 array_3,array_4,array_5 中的元素是什么?
        NSLog(@"array_3 = %@ \n array_4 = %@\n array_5 = %@",array_3,array_4,array_5);
array_3 = (
    "Micheal Jackson",
    "Susan Boyle"
) 
 array_4 = (
    "Micheal Jackson",
    "Susan Boyle"
)
 array_5 = (
    "Micheal Jackson",
    "Susan Boyle"
)


        //創(chuàng)建數(shù)組 array_6他炊,array_7
        NSMutableArray *array_6 = [[NSMutableArray alloc] initWithArray:array_3 copyItems:NO];
        NSMutableArray *array_7 = [[NSMutableArray alloc] initWithArray:array_3 copyItems:YES];
         [av_3 appendString:@" Boyle"];
        
        //請(qǐng)思考 array_6争剿,array_7中的元素是什么?
        NSLog(@"array_6 = %@ \n array_7 = %@",array_6,array_7);
        
array_6 = (
    "Micheal Jackson",
    "Susan Boyle"
) 
 array_7 = (
    "Micheal Jackson",
    Susan
)

2. NSArray對(duì)象的拷貝

下面讓我們?cè)賮?lái)看看對(duì)不可變數(shù)組NSArray對(duì)象進(jìn)行拷貝的例子:

        //1.創(chuàng)建四個(gè)可變字符串
        NSMutableString *av_0 = [NSMutableString stringWithString:@"Harry"];
        NSMutableString *av_1 = [NSMutableString stringWithString:@"Jamie"];
        NSMutableString *av_2 = [NSMutableString stringWithString:@"Micheal"];
        NSMutableString *av_3 = [NSMutableString stringWithString:@"Susan"];

        //2.創(chuàng)建一個(gè)不可變數(shù)組 array_3
        NSArray *array_3 = @[av_2,av_3];

        //3.拷貝 array_3  分別賦值給 array_4痊末,array_5
        NSMutableArray *array_4 = [array_3 mutableCopy];
        NSArray *array_5 = [array_3 copy];
        NSArray *array_6 = array_3;

        //4.修改數(shù)組 array_3 中的元素 av_2
        [av_2 appendString:@" Jackson"];

        //5.輸出數(shù)組 array_3, array_4, array_5, array_6 中的元素蚕苇,請(qǐng)先思考結(jié)果如何
        NSLog(@"array_3 = %@ \n array_4 = %@\n array_5 = %@ \n array_6 = %@",array_3,array_4,array_5,array_6);

現(xiàn)在我們也按照?qǐng)Dcopy_00.JPG中關(guān)于NSArray的總結(jié)來(lái)分析結(jié)果。當(dāng)我們調(diào)用copy方法對(duì)不可變數(shù)組NSArray的對(duì)象進(jìn)行拷貝時(shí)凿叠,是淺拷貝涩笤;而調(diào)用mutableCopy是深拷貝嚼吞。因此,當(dāng)我們通過(guò)調(diào)用copy方法對(duì)array_3進(jìn)行拷貝辆它,并賦值給array_5 誊薄,此時(shí)array_3array_5都指向堆中的同一塊內(nèi)存空間;而通過(guò)調(diào)用mutableCopy方法拷貝的結(jié)果array_4array_3指向堆中不同的內(nèi)存空間锰茉。那么當(dāng)我們改變av_2時(shí)呢蔫,array_3array_5中的av_2會(huì)變化,變成Micheal Jackson飒筑;而array_4中的av_2會(huì)不變化片吊,仍然是Micheal。但實(shí)際結(jié)果真會(huì)如此嗎协屡,讓我們一起來(lái)見(jiàn)證奇跡:

array_3 = (
    "Micheal Jackson",
    Susan
) 
 array_4 = (
    "Micheal Jackson",
    Susan
)
 array_5 = (
    "Micheal Jackson",
    Susan
) 
 array_6 = (
    "Micheal Jackson",
    Susan
)

我們重新創(chuàng)建一個(gè)NSArray對(duì)象俏脊,并賦值給array_3,并看看array_3肤晓,array_4爷贫,array_5array_6的輸出結(jié)果补憾,代碼及運(yùn)行結(jié)果如下:

   array_3 = [NSArray arrayWithObjects:av_0,av_1, nil];
   NSLog(@"array_3 = %@ \n array_4 = %@\n array_5 = %@ \n array_6 = %@",array_3,array_4,array_5,array_6);
array_3 = (
    Harry,
    Jamie
) 
 array_4 = (
    "Micheal Jackson",
    Susan
)
 array_5 = (
    "Micheal Jackson",
    Susan
) 
 array_6 = (
    "Micheal Jackson",
    Susan
)

4.關(guān)于 copy 和 mutableCopy

通過(guò)上面的兩個(gè)例子我們可看出漫萄,對(duì)NSArrayNSMutableArray對(duì)象無(wú)論通過(guò)copy方法,還是mutableCopy方法進(jìn)行拷貝盈匾,都是淺拷貝腾务。我們只拷貝了容器對(duì)象本身,并不復(fù)制其中的數(shù)據(jù)削饵。而copymutableCopy拷貝的結(jié)果 是可變對(duì)象和不可變對(duì)象岩瘦。無(wú)論當(dāng)前實(shí)例是否可變,若需要獲取其可變版本的拷貝窿撬,均應(yīng)該調(diào)用mutableCopy方法启昧。同理,若需要不可變的拷貝尤仍,則均應(yīng)該調(diào)用copy方法獲取箫津。
在Foundation框架中的所有collection類在默認(rèn)情況下都執(zhí)行淺拷貝,也就是說(shuō)只拷貝容器對(duì)象本身宰啦,而不復(fù)制其中的數(shù)據(jù)苏遥。這樣做的原因在于,容器內(nèi)的對(duì)像未必都能拷貝(即遵守copy協(xié)議)赡模,而調(diào)用者也未必想在拷貝容器時(shí)一并拷貝其中的對(duì)象田炭。

5. NSArray 和 NSMutableArray 的深拷貝

通過(guò)上面的分析我們知道,對(duì)數(shù)組對(duì)象通過(guò)copymutableCopy方法進(jìn)行拷貝漓柑,都是淺拷貝教硫。若我們想對(duì)數(shù)組進(jìn)行深拷貝叨吮,可以調(diào)用該類的初始化方法- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;來(lái)執(zhí)行深拷貝。調(diào)用該方法的前提是瞬矩,數(shù)組中的每個(gè)元素必須遵守copy 協(xié)議茶鉴。

NSArray *array_7 = @[av_0,av_1];
NSArray *array_8 = [[NSArray alloc] initWithArray:array_7 copyItems:NO];
NSArray *array_9 = [[NSArray alloc] initWithArray:array_7 copyItems:YES];
[av_0 appendString:@" Potter"];
NSLog(@"array_7 = %@ \n array_8 = %@ \n array_9 = %@ ",array_7,array_8,array_9);

flag參數(shù)設(shè)為YES,則會(huì)向數(shù)組中的每個(gè)元素發(fā)送copy消息景用,用拷貝好的元素創(chuàng)建新的數(shù)組涵叮,并將其返回給調(diào)用者。當(dāng)改變av_0時(shí)伞插,array_9中的av_0仍然是Harry割粮,而array_7array_8中的av_0則變成 Harry Potter。輸出結(jié)果如下:

array_7 = (
    "Harry Potter",
    Jamie
) 
 array_8 = (
    "Harry Potter",
    Jamie
) 
 array_9 = (
    Harry,
    Jamie
)

對(duì)于Foundation框架中的所有collection(字典媚污,數(shù)組舀瓢,集合)類都提供了深拷貝的初始化方法。但是對(duì)于自定義類耗美,因?yàn)闆](méi)有專門的深拷貝協(xié)議京髓,所以其具體的執(zhí)行方式由每個(gè)類來(lái)確定,我們只需決定自己所寫(xiě)的類是否要提供深拷貝的方法即可商架。此外朵锣,遵守了copy 協(xié)議的對(duì)象不一定都會(huì)執(zhí)行深拷貝。在大部分情況下甸私,執(zhí)行的都是淺拷貝。如果需要在某對(duì)象上執(zhí)行深拷貝飞傀,除非該文檔說(shuō)明它是用深拷貝來(lái)實(shí)現(xiàn)copy 協(xié)議的皇型,否則要么尋找能夠執(zhí)行深拷貝的相關(guān)方法,要么自己編寫(xiě)方法實(shí)現(xiàn)深拷貝砸烦。

6.深拷貝和淺拷貝

用一個(gè)與實(shí)例對(duì)象相同的內(nèi)容弃鸦,生成一個(gè)新的對(duì)象,這個(gè)過(guò)程就是復(fù)制幢痘。其中只復(fù)制對(duì)象的指針成為淺拷貝唬格,而復(fù)制具有新的內(nèi)存空間的對(duì)象成為深拷貝

圖A.png

圖B.jpg

圖C.png

由上圖可以看出颜说,變量A指向了一個(gè)對(duì)象购岗,而這個(gè)對(duì)象的實(shí)例變量又指向了另一個(gè)對(duì)象。把變量A復(fù)制到變量B時(shí)门粪,圖A只復(fù)制對(duì)象的指針喊积,將對(duì)象代入到變量中;圖B將變量A指向的對(duì)象原樣復(fù)制一份玄妈,并通過(guò)指針來(lái)共享這個(gè)對(duì)象和復(fù)制體中的實(shí)例變量乾吻;圖C復(fù)制對(duì)象中的實(shí)例變量髓梅,并遞歸的進(jìn)行對(duì)象復(fù)制。
下圖是蘋(píng)果官方文檔關(guān)于深拷貝和淺拷貝的說(shuō)明示例圖:
圖 D.png

7.Swift 4.2 專題模塊

Swift 4.2 基礎(chǔ)專題詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绎签,一起剝皮案震驚了整個(gè)濱河市枯饿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诡必,老刑警劉巖奢方,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異擒权,居然都是意外死亡袱巨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門碳抄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)愉老,“玉大人,你說(shuō)我怎么就攤上這事剖效〖等耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵璧尸,是天一觀的道長(zhǎng)咒林。 經(jīng)常有香客問(wèn)我,道長(zhǎng)爷光,這世上最難降的妖魔是什么垫竞? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮蛀序,結(jié)果婚禮上欢瞪,老公的妹妹穿的比我還像新娘。我一直安慰自己徐裸,他們只是感情好遣鼓,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著重贺,像睡著了一般骑祟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上气笙,一...
    開(kāi)封第一講書(shū)人閱讀 52,584評(píng)論 1 312
  • 那天次企,我揣著相機(jī)與錄音,去河邊找鬼健民。 笑死抒巢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秉犹。 我是一名探鬼主播蛉谜,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼稚晚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了型诚?” 一聲冷哼從身側(cè)響起客燕,我...
    開(kāi)封第一講書(shū)人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狰贯,沒(méi)想到半個(gè)月后也搓,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涵紊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年傍妒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摸柄。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颤练,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驱负,到底是詐尸還是另有隱情嗦玖,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布跃脊,位于F島的核電站宇挫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏酪术。R本人自食惡果不足惜器瘪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绘雁。 院中可真熱鬧娱局,春花似錦、人聲如沸咧七。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)继阻。三九已至,卻和暖如春废酷,著一層夾襖步出監(jiān)牢的瞬間瘟檩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工澈蟆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墨辛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓趴俘,卻偏偏與公主長(zhǎng)得像睹簇,于是被迫代替她去往敵國(guó)和親奏赘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容