淺復制和深復制 指針拷貝 對象拷貝

來源: https://www.zybuluo.com/MicroCai/note/50592

概念

對象拷貝有兩種方式:淺復制和深復制兄渺。顧名思義择浊,淺復制,并不拷貝對象本身刹碾,僅僅是拷貝指向對象的指針;深復制是直接拷貝整個對象內(nèi)存到另一塊內(nèi)存中座柱。

一圖以蔽之

再簡單些說:淺復制就是指針拷貝教硫;深復制就是內(nèi)容拷貝。

集合的淺復制 (shallow copy)

集合的淺復制有非常多種方法辆布。當你進行淺復制時瞬矩,會向原始的集合發(fā)送retain消息,引用計數(shù)加1锋玲,同時指針被拷貝到新的集合景用。

現(xiàn)在讓我們看一些淺復制的例子:

NSArray*shallowCopyArray=[someArray copyWithZone:nil];

NSSet*shallowCopySet=[NSSetmutableCopyWithZone:nil];

NSDictionary*shallowCopyDict=[[NSDictionaryalloc]initWithDictionary:someDictionary copyItems:NO];

集合的深復制 (deep copy)

集合的深復制有兩種方法〔氧澹可以用 initWithArray:copyItems: 將第二個參數(shù)設置為YES即可深復制伞插,如

NSDictionaryshallowCopyDict=[[NSDictionaryalloc]initWithDictionary:someDictionary copyItems:YES];

如果你用這種方法深復制,集合里的每個對象都會收到 copyWithZone: 消息盾碗。如果集合里的對象遵循 NSCopying 協(xié)議媚污,那么對象就會被深復制到新的集合。如果對象沒有遵循 NSCopying 協(xié)議廷雅,而嘗試用這種方法進行深復制耗美,會在運行時出錯。copyWithZone: 這種拷貝方式只能夠提供一層內(nèi)存拷貝(one-level-deep copy)航缀,而非真正的深復制商架。

第二個方法是將集合進行歸檔(archive),然后解檔(unarchive)芥玉,如:

NSArray*trueDeepCopyArray=[NSKeyedUnarchiverunarchiveObjectWithData:[NSKeyedArchiverarchivedDataWithRootObject:oldArray]];

集合的單層深復制 (one-level-deep copy)

看到這里蛇摸,有同學會問:如果在多層數(shù)組中,對第一層進行內(nèi)容拷貝灿巧,其它層進行指針拷貝赶袄,這種情況是屬于深復制,還是淺復制抠藕?對此饿肺,蘋果官網(wǎng)文檔有這樣一句話描述

This kind of copy is only capable of producing a one-level-deep copy. If you only need a one-level-deep copy...

If you need a true deep copy, such as when you have an array of arrays...

從文中可以看出,蘋果認為這種復制不是真正的深復制幢痘,而是將其稱為單層深復制(one-level-deep copy)唬格。因此,網(wǎng)上有人對淺復制、深復制购岗、單層深復制做了概念區(qū)分汰聋。

淺復制(shallow copy):在淺復制操作時,對于被復制對象的每一層都是指針復制喊积。

深復制(one-level-deep copy):在深復制操作時烹困,對于被復制對象,至少有一層是深復制乾吻。

完全復制(real-deep copy):在完全復制操作時髓梅,對于被復制對象的每一層都是對象復制。

當然绎签,這些都是概念性的東西枯饿,沒有必要糾結于此。只要知道進行拷貝操作時诡必,被拷貝的是指針還是內(nèi)容即可奢方。

系統(tǒng)對象的copy與mutableCopy方法

不管是集合類對象,還是非集合類對象爸舒,接收到copy和mutableCopy消息時蟋字,都遵循以下準則:

copy返回imutable對象;所以扭勉,如果對copy返回值使用mutable對象接口就會crash鹊奖;

mutableCopy返回mutable對象;

下面將針對非集合類對象和集合類對象的copy和mutableCopy方法進行具體的闡述

1涂炎、非集合類對象的copy與mutableCopy

系統(tǒng)非集合類對象指的是 NSString, NSNumber ... 之類的對象忠聚。下面先看個非集合類immutable對象拷貝的例子

NSString*string=@"origin";

NSString*stringCopy=[stringcopy];

NSMutableString*stringMCopy=[stringmutableCopy];

通過查看內(nèi)存,可以看到 stringCopy 和 string 的地址是一樣璧尸,進行了指針拷貝咒林;而 stringMCopy 的地址和 string 不一樣,進行了內(nèi)容拷貝爷光;

再看mutable對象拷貝例子

NSMutableString*string=[NSMutableStringstringWithString:@"origin"];

//copy

NSString*stringCopy=[stringcopy];

NSMutableString*mStringCopy=[stringcopy];

NSMutableString*stringMCopy=[stringmutableCopy];

//change value

[mStringCopy appendString:@"mm"];//crash

[stringappendString:@" origion!"];

[stringMCopy appendString:@"!!"];

運行以上代碼,會在第7行crash澎粟,原因就是 copy 返回的對象是 immutable 對象蛀序。注釋第7行后再運行,查看內(nèi)存活烙,發(fā)現(xiàn) string徐裸、stringCopy、mStringCopy啸盏、stringMCopy 四個對象的內(nèi)存地址都不一樣重贺,說明此時都是做內(nèi)容拷貝。

綜上兩個例子,我們可以得出結論:

在非集合類對象中:對immutable對象進行copy操作气笙,是指針復制次企,mutableCopy操作時內(nèi)容復制;對mutable對象進行copy和mutableCopy都是內(nèi)容復制潜圃。用代碼簡單表示如下:

[immutableObject copy] // 淺復制

[immutableObject mutableCopy] //深復制

[mutableObject copy] //深復制

[mutableObject mutableCopy] //深復制

2缸棵、集合類對象的copy與mutableCopy

集合類對象是指NSArray、NSDictionary谭期、NSSet ... 之類的對象堵第。下面先看集合類immutable對象使用copy和mutableCopy的一個例子:

NSArray*array=@[@[@"a",@"b"],@[@"c",@"d"];

NSArray*copyArray=[array copy];

NSMutableArray*mCopyArray=[array mutableCopy];

查看內(nèi)容,可以看到copyArray和array的地址是一樣的隧出,而mCopyArray和array的地址是不同的踏志。說明copy操作進行了指針拷貝,mutableCopy進行了內(nèi)容拷貝胀瞪。但需要強調(diào)的是:此處的內(nèi)容拷貝针余,僅僅是拷貝array這個對象,array集合內(nèi)部的元素仍然是指針拷貝赏廓。這和上面的非集合immutable對象的拷貝還是挺相似的涵紊,那么mutable對象的拷貝會不會類似呢?我們繼續(xù)往下幔摸,看mutable對象拷貝的例子:

NSMutableArray*array=[NSMutableArrayarrayWithObjects:[NSMutableStringstringWithString:@"a"],@"b",@"c",nil];

NSArray*copyArray=[array copy];

NSMutableArray*mCopyArray=[array mutableCopy];

查看內(nèi)存摸柄,如我們所料,copyArray既忆、mCopyArray和array的內(nèi)存地址都不一樣驱负,說明copyArray、mCopyArray都對array進行了內(nèi)容拷貝患雇。同樣跃脊,我們可以得出結論:

在集合類對象中,對immutable對象進行copy苛吱,是指針復制酪术,mutableCopy是內(nèi)容復制;對mutable對象進行copy和mutableCopy都是內(nèi)容復制翠储。但是:集合對象的內(nèi)容復制僅限于對象本身绘雁,對象元素仍然是指針復制。用代碼簡單表示如下:

[immutableObject copy] // 淺復制

[immutableObject mutableCopy] //單層深復制

[mutableObject copy] //單層深復制

[mutableObject mutableCopy] //單層深復制

這個代碼結論和非集合類的非常相似援所。

這時候庐舟,是不是有人要問了,如果要對集合對象復制元素怎么辦住拭?有這疑問的同學不妨回頭看看集合的深復制挪略。

好了历帚,深復制與淺復制就講到這里。

最后說個題外的東西杠娱,在搜集資料的過程中挽牢,發(fā)現(xiàn)一個有可能犯錯的點

NSString*str=@"string";

str=@"newString";

上面這段代碼,在執(zhí)行第二行代碼后墨辛,內(nèi)存地址發(fā)生了變化卓研。乍一看,有點意外睹簇。按照 C 語言的經(jīng)驗奏赘,初始化一個字符串之后,字符串的首地址就被確定下來太惠,不管之后如何修改字符串內(nèi)容磨淌,這個地址都不會改變。但此處第二行并不是對 str 指向的內(nèi)存地址重新賦值凿渊,因為賦值操作符左邊的 str 是一個指針梁只,也就是說此處修改的是內(nèi)存地址。

所以第二行應該這樣理解:將@"newStirng"當做一個新的對象埃脏,將這段對象的內(nèi)存地址賦值給str搪锣。

我有如下的兩個方法查看內(nèi)存地址

p str會打印對象本身的內(nèi)存地址和對象內(nèi)容

(lldb)p str

(NSString*)$0=0x000000010c913680@"a"

po &str則打印的是引用對象的指針所在的地址

(lldb)po&str

0x00007fff532fb6c0

參考文檔

[1]Apple Collections Programming Topics: Copying Collections

[2]iPhone Dev:iOS開發(fā)之深拷貝與淺拷貝(mutableCopy與Copy)詳解(博文可能有紕漏,童鞋仔細閱讀親自驗證)

[3]Blog:copy 與 mutableCopy

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末彩掐,一起剝皮案震驚了整個濱河市构舟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堵幽,老刑警劉巖狗超,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異朴下,居然都是意外死亡努咐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門殴胧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渗稍,“玉大人,你說我怎么就攤上這事团滥∶馕福” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵惫撰,是天一觀的道長。 經(jīng)常有香客問我躺涝,道長厨钻,這世上最難降的妖魔是什么扼雏? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮夯膀,結果婚禮上诗充,老公的妹妹穿的比我還像新娘。我一直安慰自己诱建,他們只是感情好蝴蜓,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俺猿,像睡著了一般茎匠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上押袍,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天诵冒,我揣著相機與錄音,去河邊找鬼谊惭。 笑死汽馋,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的圈盔。 我是一名探鬼主播豹芯,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼驱敲!你這毒婦竟也來了铁蹈?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤癌佩,失蹤者是張志新(化名)和其女友劉穎木缝,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體围辙,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡我碟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了姚建。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矫俺。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖掸冤,靈堂內(nèi)的尸體忽然破棺而出厘托,到底是詐尸還是另有隱情,我是刑警寧澤稿湿,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布铅匹,位于F島的核電站,受9級特大地震影響饺藤,放射性物質發(fā)生泄漏包斑。R本人自食惡果不足惜流礁,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望罗丰。 院中可真熱鬧神帅,春花似錦、人聲如沸萌抵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绍填。三九已至霎桅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沐兰,已是汗流浹背哆档。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留住闯,地道東北人瓜浸。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像比原,于是被迫代替她去往敵國和親插佛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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