iOS 圖文并茂的帶你了解深拷貝與淺拷貝

轉(zhuǎn)載
一脏款、概念與總結(jié)

1、淺拷貝

淺拷貝就是對內(nèi)存地址的復(fù)制裤园,讓目標對象指針和源對象指向同一片內(nèi)存空間撤师,當(dāng)內(nèi)存銷毀的時候,指向這片內(nèi)存的幾個指針需要重新定義才可以使用拧揽,要不然會成為野指針剃盾。

淺拷貝就是拷貝指向原來對象的指針,使原對象的引用計數(shù)+1淤袜,可以理解為創(chuàng)建了一個指向原對象的新指針而已痒谴,并沒有創(chuàng)建一個全新的對象。

2铡羡、深拷貝

深拷貝是指拷貝對象的具體內(nèi)容积蔚,而內(nèi)存地址是自主分配的,拷貝結(jié)束之后烦周,兩個對象雖然存的值是相同的尽爆,但是內(nèi)存地址不一樣,兩個對象也互不影響读慎,互不干涉教翩。

深拷貝就是拷貝出和原來僅僅是值一樣,但是內(nèi)存地址完全不一樣的新的對象贪壳,創(chuàng)建后和原對象沒有任何關(guān)系饱亿。

3、總結(jié):

深拷貝就是內(nèi)容拷貝,淺拷貝就是指針拷貝彪笼。本質(zhì)區(qū)別在于:

是否開啟新的內(nèi)存地址

是否影響內(nèi)存地址的引用計數(shù)

** 二钻注、示例分析**

在iOS中深拷貝與淺拷貝要更加的復(fù)雜,涉及到容器與非容器配猫、可變與不可變對象的copy與mutableCopy幅恋。下面用示例逐一分析:

1、非集合對象的copymutableCopy

**1.1 不可變對象NSString **

- (void) noMutableNSStringTest
{
    NSString *str1 = @"test001";
    
    NSMutableString *str2 = [str1 copy];
    //copy返回的是不可變對象泵肄,str2不能被修改捆交,因此會發(fā)生崩潰
    //[str2 appendString:@"test"];
    
    NSMutableString *str3 = [str1 mutableCopy];
    [str3 appendString:@"modify"];
    
    NSLog(@"str1:%p - %@ \r\n",str1,str1);
    NSLog(@"str2:%p - %@ \r\n",str2,str2);
    NSLog(@"str3:%p - %@ \r\n",str3,str3);
}

打印結(jié)果:

2017-07-20 18:02:10.642 beck.wang[1306:169414] str1:0x106abdbd0 - test001 
2017-07-20 18:02:10.643 beck.wang[1306:169414] str2:0x106abdbd0 - test001 
2017-07-20 18:02:10.643 beck.wang[1306:169414] str3:0x608000260940 - test001modify 

分析:str1、str2地址相同并且與str3地址不同腐巢,NSString的copy是淺拷貝品追,且copy返回的對象是不可變對象;mutableCopy是深拷貝冯丙。

1.2 可變對象NSMutableString

- (void) mutableNSStringTest
{
    NSMutableString *mstr1 = [NSMutableString stringWithString:@"test002"];
    
    NSMutableString *mstr2 = [mstr1 copy];
    //copy返回的是不可變對象肉瓦,mstr2不能被修改,因此會發(fā)生崩潰
    //[str2 appendString:@"test"];
    
    NSMutableString *mstr3 = [mstr1 mutableCopy];
    [mstr3 appendString:@"modify"];
    
    NSLog(@"mstr1:%p - %@ \r\n",mstr1,mstr1);
    NSLog(@"mstr2:%p - %@ \r\n",mstr2,mstr2);
    NSLog(@"mstr3:%p - %@ \r\n",mstr3,mstr3);
}

打印結(jié)果:

2017-07-20 18:14:35.789 beck.wang[1433:180881] mstr1:0x610000075e40 - test002 
2017-07-20 18:14:35.790 beck.wang[1433:180881] mstr2:0xa323030747365747 - test002 
2017-07-20 18:14:35.790 beck.wang[1433:180881] mstr3:0x610000074480 - test002modify 

分析:mstr1胃惜、mstr2泞莉、mstr3 地址都不同,NSMutableString對象copy與mutableCopy都是深拷貝船殉,且copy返回的對象是不可變對象鲫趁。

2、集合對象的copymutableCopy

2.1 不可變對象NSArray

- (void) mutableNSArrayTest
{
    NSArray *arry1 = [[NSArray alloc] initWithObjects:@"value1", @"value2",nil];
    
    NSArray *arry2 = [arry1 copy];
    NSArray *arry3 = [arry1 mutableCopy];
    
    NSLog(@"arry1:%p - %@ \r\n",arry1,arry1);
    NSLog(@"arry2:%p - %@ \r\n",arry2,arry2);
    NSLog(@"arry3:%p - %@ \r\n",arry3,arry3);
}

打印結(jié)果:

2017-07-20 18:33:53.707 beck.wang[1502:194476] arry1:0x60800003b480 - (
    value1,
    value2
) 
2017-07-20 18:33:53.708 beck.wang[1502:194476] arry2:0x60800003b480 - (
    value1,
    value2
) 
2017-07-20 18:33:53.708 beck.wang[1502:194476] arry3:0x60800004cd20 - (
    value1,
    value2
) 

分析:arry1利虫、arry2 地址一樣挨厚,arr3 地址不一樣,NSArray的copy是淺拷貝列吼,且copy返回的對象是不可變對象幽崩;mutableCopy是深拷貝苦始。

2.2 可變對象NSMutableArray

- (void) NSMutableArrayTest
{
    NSMutableArray *marry1 = [[NSMutableArray alloc] initWithObjects:@"value1", @"value2",nil];
    
    NSMutableArray *marry2 = [marry1 copy];
    
    //copy返回的是不可變對象寞钥,marry2不能被修改,因此會崩潰
    //[marry2 addObject:@"value3"];
    
    NSMutableArray *marry3 = [marry1 mutableCopy];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);
    NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);
}

打印結(jié)果:

2017-07-20 18:55:43.243 beck.wang[1577:204641] marry1:0x600000048d60 - (
    value1,
    value2
) 
2017-07-20 18:55:43.244 beck.wang[1577:204641] marry2:0x600000026000 - (
    value1,
    value2
) 
2017-07-20 18:55:43.244 beck.wang[1577:204641] marry3:0x6000000494b0 - (
    value1,
    value2
) 

分析:marry1陌选、marry2理郑、marr3 地址都不一樣,NSMutableArray對象copy與mutableCopy都是深拷貝咨油,且copy返回的對象是不可變對象您炉。

特別注意的是:對于集合類的可變對象來說,深拷貝并非嚴格意義上的深復(fù)制役电,只能算是單層深復(fù)制赚爵,即雖然新開辟了內(nèi)存地址,但是存放在內(nèi)存上的值(也就是數(shù)組里的元素仍然之鄉(xiāng)員數(shù)組元素值,并沒有另外復(fù)制一份)冀膝,這就叫做單層深復(fù)制唁奢。
舉例說明:

- (void)singleNSMutableArrayTest
{
    NSMutableArray *marry1 = [[NSMutableArray alloc] init];
    
    NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
    NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
    
    [marry1 addObject:mstr1];
    [marry1 addObject:mstr2];
    
    NSMutableArray *marry2 = [marry1 copy];
    NSMutableArray *marry3 = [marry1 mutableCopy];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);
    NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry2[0],marry2[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry3[0],marry3[1]);
    
    NSLog(@"\r\n------------------修改原值后------------------------\r\n");
    [mstr1 appendFormat:@"aaa"];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);
    NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry2[0],marry2[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry3[0],marry3[1]);
}

打印結(jié)果:

2017-07-20 19:48:24.539 beck.wang[1750:230132] marry1:0x60800004ae00 - (
    value1,
    value2
) 
2017-07-20 19:48:24.539 beck.wang[1750:230132] marry2:0x608000023f00 - (
    value1,
    value2
) 
2017-07-20 19:48:24.539 beck.wang[1750:230132] marry3:0x60800004abc0 - (
    value1,
    value2
) 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 數(shù)組元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 數(shù)組元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 數(shù)組元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 
------------------修改原值后------------------------
2017-07-20 19:48:24.540 beck.wang[1750:230132] marry1:0x60800004ae00 - (
    value1aaa,
    value2
) 
2017-07-20 19:48:24.540 beck.wang[1750:230132] marry2:0x608000023f00 - (
    value1aaa,
    value2
) 
2017-07-20 19:48:24.540 beck.wang[1750:230132] marry3:0x60800004abc0 - (
    value1aaa,
    value2
) 
2017-07-20 19:48:24.541 beck.wang[1750:230132] 數(shù)組元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.541 beck.wang[1750:230132] 數(shù)組元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.541 beck.wang[1750:230132] 數(shù)組元素地址:value1:0x60800006df40 - value2:0x60800006cb40 

分析:在修改原值之前,marry1窝剖、marry2麻掸、marr3 地址都不一樣,很明顯copy和mutableCopy都是深拷貝赐纱,但是從修改原值后的打印結(jié)果來看脊奋,這里的深拷貝只是單層深拷貝:新開辟了內(nèi)存地址,但是數(shù)組中的值還是指向原數(shù)組的疙描,這樣才能在修改原值后诚隙,marry2 marr3中的值都修改了。另外淫痰,從打印的數(shù)組元素地址可以很明顯的看出來最楷,修改前后marry1、marry待错、marr3的數(shù)組元素地址都是一模一樣的籽孙,更加佐證了這一點。

2.3 思維擴展:集合對象的完全深拷貝

2.2中提到了集合類的對象來說火俄,深拷貝只是單層深拷貝犯建,那有沒有辦法實現(xiàn)每一層都深拷貝呢?回答是肯定的瓜客,目前我們可以這么做:

(1)歸檔解檔大法

- (void) deplyFullCopy
{
    NSMutableArray *marry1 = [[NSMutableArray alloc] init];
    
    NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
    NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
    
    [marry1 addObject:mstr1];
    [marry1 addObject:mstr2];
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:marry1];
    NSArray *marray2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}

打印結(jié)果:

2017-07-20 20:04:38.726 beck.wang[1833:242158] marry1:0x600000048a00 - (
    value1,
    value2
) 
2017-07-20 20:04:38.726 beck.wang[1833:242158] marry2:0x600000049780 - (
    value1,
    value2
) 
2017-07-20 20:04:38.726 beck.wang[1833:242158] 數(shù)組元素地址:value1:0x600000066300 - value2:0x600000067000 
2017-07-20 20:04:38.726 beck.wang[1833:242158] 數(shù)組元素地址:value1:0x600000066740 - value2:0x600000066f40 

分析:我們可以看到适瓦,開辟了新的內(nèi)存地址的同時,數(shù)組元素的指針地址也不同了谱仪,實現(xiàn)了完全的深拷貝玻熙。

(2)- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;

- (void) deplyFullCopy2
{
    NSMutableArray *marry1 = [[NSMutableArray alloc] init];
    
    NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
    NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
    
    [marry1 addObject:mstr1];
    [marry1 addObject:mstr2];
    
    NSArray *marray2 = [[NSArray alloc] initWithArray:marry1 copyItems:YES];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}

打印結(jié)果:

2017-07-20 20:08:04.201 beck.wang[1868:246161] marry1:0x610000050320 - (
    value1,
    value2
) 
2017-07-20 20:08:04.202 beck.wang[1868:246161] marry2:0x6100002214c0 - (
    value1,
    value2
) 
2017-07-20 20:08:04.202 beck.wang[1868:246161] 數(shù)組元素地址:value1:0x610000265600 - value2:0x610000266400 
2017-07-20 20:08:04.202 beck.wang[1868:246161] 數(shù)組元素地址:value1:0xa003165756c61766 - value2:0xa003265756c61766 

分析:同上。

三疯攒、準則

No1:可變對象的copymutableCopy方法都是深拷貝(區(qū)別完全深拷貝與單層深拷貝) 嗦随。

No2:不可變對象的copy方法是淺拷貝,mutableCopy方法是深拷貝敬尺。

No3:copy方法返回的對象都是不可變對象枚尼。

萬語千言匯成一張圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市砂吞,隨后出現(xiàn)的幾起案子署恍,更是在濱河造成了極大的恐慌,老刑警劉巖蜻直,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盯质,死亡現(xiàn)場離奇詭異袁串,居然都是意外死亡,警方通過查閱死者的電腦和手機呼巷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門般婆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人朵逝,你說我怎么就攤上這事蔚袍。” “怎么了配名?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵啤咽,是天一觀的道長。 經(jīng)常有香客問我渠脉,道長宇整,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任芋膘,我火速辦了婚禮鳞青,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘为朋。我一直安慰自己臂拓,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布习寸。 她就那樣靜靜地躺著胶惰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霞溪。 梳的紋絲不亂的頭發(fā)上孵滞,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音鸯匹,去河邊找鬼坊饶。 笑死,一個胖子當(dāng)著我的面吹牛殴蓬,可吹牛的內(nèi)容都是我干的匿级。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼科雳,長吁一口氣:“原來是場噩夢啊……” “哼根蟹!你這毒婦竟也來了脓杉?” 一聲冷哼從身側(cè)響起糟秘,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎球散,沒想到半個月后尿赚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年凌净,在試婚紗的時候發(fā)現(xiàn)自己被綠了悲龟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡冰寻,死狀恐怖须教,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斩芭,我是刑警寧澤轻腺,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站划乖,受9級特大地震影響贬养,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜琴庵,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一误算、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧迷殿,春花似錦儿礼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至止邮,卻和暖如春这橙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背导披。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工屈扎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撩匕。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓鹰晨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親止毕。 傳聞我的和親對象是個殘疾皇子模蜡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

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

  • 1、對象拷貝有兩種方式:淺復(fù)制和深復(fù)制扁凛。顧名思義忍疾,淺復(fù)制,并不拷貝對象本身谨朝,僅僅是拷貝指向?qū)ο蟮闹羔樎倍剩簧顝?fù)制是直接...
    滴答大閱讀 772評論 0 2
  • 導(dǎo)讀 最近經(jīng)常在關(guān)注的公眾號或者技術(shù)網(wǎng)站看到關(guān)于 iOS 深拷貝與淺拷貝的話題甥绿。看到一篇技術(shù)文章则披,點擊收藏或者只是...
    獨木舟的木閱讀 674評論 0 8
  • 這篇文章主要翻譯apple的官方文檔和其他類似博文的學(xué)習(xí)記錄 Copying Collections 概念 拷貝的...
    devZhang閱讀 3,028評論 3 23
  • 概念 在Objective-C中并不是所有的對象都支持Copy共缕,MutableCopy,遵守NSCopying協(xié)議...
    LeoAu閱讀 8,778評論 10 28
  • 美好的一天伴隨我的問候開始士复!今天是公歷12月11日图谷,星期一,農(nóng)歷十月二十四阱洪,請關(guān)注天氣變化:哈爾濱蜓萄,多云,-18℃...
    希望在線閱讀 78評論 0 0