Copy vs MutableCopy, 淺復(fù)制和深復(fù)制

copy關(guān)鍵字和retain關(guān)鍵字

首先說明一個重要的區(qū)別——二者的不同之處在setter方法中揭芍。

  • copy關(guān)鍵字:

假如有如下代碼:

 @property (nonatomic,copy)NSObject *objA;
 NSObject *objB = _objA;

則賦值語句等效于:

[oldValue release];
oldValue = [newValue copy];

這樣可以避免new值變化時影響old值称杨。

  • retain關(guān)鍵字:

以下代碼:

 @property (nonatomic,retain)NSObject *objA;
 NSObject *objB = _objA;

等同于:

[oldValue release];
oldValue = [newValue retain];

一個小tips:一定要把copy屬性關(guān)鍵字用于具有可變子類的不可變對象姑原。

不過悬而,如果對可變對象使用了copy屬性,會如何呢锭汛?來看代碼:(這里我們直接對a進行copy操作笨奠,這和使用copy屬性關(guān)鍵字具有等同的效果)

    NSMutableArray *a = [NSMutableArray arrayWithObjects:@0,@1,@2, nil];
    NSMutableArray *b = [a copy];
QQ20171022-104953.png

因此,定義可變屬性時不要使用copy關(guān)鍵字店乐,因為在給這個屬性賦值的時候艰躺,該屬性會自動變成不可變類型。如果對該屬性調(diào)用可變類型專有的方法眨八,則會發(fā)生崩潰腺兴。

Block屬性的關(guān)鍵字

因為block在什么時候執(zhí)行是未知的廉侧,所以如果block里外部對象被提前釋放了页响,那么如果這時候block執(zhí)行了,程序就會崩潰段誊。

所以對于Block來說闰蚕,我們一般都用copy關(guān)鍵字修飾.

復(fù)制出的對象的可變性

  1. 可變對象的復(fù)制:

對可變對象的調(diào)用還是剛剛的代碼,不過我們增加一個變量C來測試:

        NSMutableArray *a = [NSMutableArray arrayWithObjects:@0,@1,@2, nil];
    NSMutableArray *b = [a copy];
    NSMutableArray *c = [a mutableCopy];

打印连舍,得到:

因此没陡,對可變對象調(diào)用copy,得到不可變對象;對可變對象調(diào)用mutableCopy盼玄,得到可變對象贴彼。

  1. 不可變對象的復(fù)制:

     NSArray *a = [NSArray arrayWithObjects:@0,@1,@2, nil];
     NSArray *b = [a copy];
     NSArray *c = [a mutableCopy];
    

打印:

QQ20171022-110141.png

因此埃儿,對可變對象調(diào)用copy器仗,得到不可變對象;對可變對象調(diào)用mutableCopy童番,得到可變對象精钮。

淺復(fù)制和深復(fù)制

  1. 對可變對象進行測試:

     NSMutableArray *a = [NSMutableArray arrayWithCapacity:3];
     NSMutableArray *b = [a copy];
     NSMutableArray *c = [a mutableCopy];
     NSLog(@"Address of a:%d",a);
     NSLog(@"Address of b:%d",b);
     NSLog(@"Address of c:%d",c);
    

    輸出:

QQ20171022-113756.png

可以看到,三個地址都不一樣剃斧,也就是說轨香,對一個可變類型,無論調(diào)用copy 還是mutableCopy悯衬,都是進行了深復(fù)制跋选。

  1. 對不可變對象進行測試:

     NSArray *a = [NSArray arrayWithObject:@1];
     NSMutableArray *b = [a copy];
     NSMutableArray *c = [a mutableCopy];
     NSLog(@"Address of a:%d",a);
     NSLog(@"Address of b:%d",b);
     NSLog(@"Address of c:%d",c);
    
QQ20171022-114030.png

對可變對象估蹄,copy進行淺復(fù)制,mutableCopy進行深復(fù)制。

集合類復(fù)制的深淺傍睹、可變性問題

剛剛我們看到的都是只有“一層”的集合⊥痰桑現(xiàn)在我們再來看一下當集合的成員也是集合類的時候偷拔,復(fù)制的情況廓块。

  • 淺復(fù)制

首先明確一點:集合類本身的深復(fù)制,并不代表其成員也進行了深復(fù)制买决。用一張?zhí)O果文檔的圖來表示:

WX20171022-230027.png

左側(cè)是淺復(fù)制沛婴,右側(cè)是深復(fù)制。然而很多人都把左側(cè)的這種當成了集合的深復(fù)制督赤,這是需要注意的一個誤區(qū)嘁灯。

進行淺復(fù)制有很多方式,但這里著重說明一種方式:

    NSArray *shallowCopyArray = [someArray copyWithZone:nil];
    NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];

注意這里躲舌,方法 initWithDictionary:copyItems:第二個參數(shù)如果填NO丑婿,得到的僅僅是對最外層集合對象的深復(fù)制,而其內(nèi)部成員都只是接收到一個retain消息没卸。

  • 單層深復(fù)制
    如果方法 initWithDictionary:copyItems:第二個參數(shù)填YES羹奉,最外層集合對象被深復(fù)制,并且其內(nèi)部第一層成員(可能是非容器類對象例如String约计,也可能是容器類對象)都收到copy消息诀拭。因此,如果其第一層內(nèi)部成員是可變的煤蚌,那么該方法調(diào)用的結(jié)果是耕挨,第一層所有可變成員被深復(fù)制细卧,而所有第一層不可變成員(如果有的話)會被淺復(fù)制。

注意俗孝,如果接收到copy消息的成員沒有遵循NSCopying協(xié)議酒甸,則程序?qū)罎ⅰ?/em>

  • 全層深復(fù)制

如果希望集合類本身及其所有層都被深復(fù)制,則可以對集合類先歸檔再解檔赋铝。當然,這么操作的前提是所有成員都遵循了NSCopying協(xié)議沽瘦。

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
      [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
  • 各種復(fù)制方式的可變性

當我們對集合進行復(fù)制操作時革骨,集合類和其成員的可變性都會受到影響。

  1. 讓表層集合對象成為immutable對象析恋。其所有成員的可變性保持原樣良哲。

  2. 第二參數(shù)設(shè)置為NO,會讓表層集合對象的可變性和創(chuàng)建它的類型一致助隧。其所有成員的可變性保持原樣筑凫。

  3. 第二參數(shù)設(shè)置為YES,會讓表層集合對象的可變性和創(chuàng)建它的類型一致并村。第二層成員變?yōu)閕mmutable的巍实。其所有成員的可變性保持原樣。

下集預(yù)告

    NSString *a = @"a";
    NSString *b = [a copy];
    NSString *c = [a mutableCopy];
    NSLog(@"a地址:%d,b地址:%d,c地址:%d",a,b,c);

打印哩牍,得到:

QQ20171022-111834.png

可以看到棚潦,如果使用一個字符串常量給a賦值,則copy生成的是不可變對象膝昆,且是淺拷貝丸边。關(guān)于字符串的問題,我會另外開一篇文章來探討荚孵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妹窖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子收叶,更是在濱河造成了極大的恐慌骄呼,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滔驾,死亡現(xiàn)場離奇詭異谒麦,居然都是意外死亡,警方通過查閱死者的電腦和手機哆致,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門绕德,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摊阀,你說我怎么就攤上這事耻蛇∽俚牛” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵臣咖,是天一觀的道長跃捣。 經(jīng)常有香客問我,道長夺蛇,這世上最難降的妖魔是什么疚漆? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮刁赦,結(jié)果婚禮上娶聘,老公的妹妹穿的比我還像新娘。我一直安慰自己甚脉,他們只是感情好丸升,可當我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著牺氨,像睡著了一般狡耻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上猴凹,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天夷狰,我揣著相機與錄音,去河邊找鬼精堕。 笑死孵淘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的歹篓。 我是一名探鬼主播瘫证,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼庄撮!你這毒婦竟也來了背捌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤洞斯,失蹤者是張志新(化名)和其女友劉穎毡庆,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烙如,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡么抗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亚铁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝇刀。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖徘溢,靈堂內(nèi)的尸體忽然破棺而出吞琐,到底是詐尸還是另有隱情捆探,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布站粟,位于F島的核電站黍图,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏奴烙。R本人自食惡果不足惜助被,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望切诀。 院中可真熱鬧恰起,春花似錦、人聲如沸趾牧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翘单。三九已至,卻和暖如春蹦渣,著一層夾襖步出監(jiān)牢的瞬間哄芜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工柬唯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留认臊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓锄奢,卻偏偏與公主長得像失晴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拘央,可洞房花燭夜當晚...
    茶點故事閱讀 45,573評論 2 359

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