?iOS中的深拷貝和淺拷貝,你真的理解了嗎?

首先分類一下:(1) 非容器 , 容器 : (2) 不可變對(duì)象,可變對(duì)象

\1. 非容器不可變對(duì)象丐箩,比如NSString

2.非容器可變對(duì)象:比如NSMutableString

3.容器類不可變對(duì)象: 比如NSArray

4.容器類可變對(duì)象: 比如NSMutableArray

在觀察深淺拷貝之前先得了解一下retain茅撞,copy和mutableCopy的特點(diǎn)顽爹,特點(diǎn)如下:

1.retain:始終是淺復(fù)制七咧。引用計(jì)數(shù)每次加一。返回對(duì)象是否可變與被復(fù)制的對(duì)象保持一致猾蒂。(所以后面不再舉例,需要測(cè)試的在手動(dòng)管理上)

2.copy:對(duì)于可變對(duì)象為深復(fù)制悠夯,引用計(jì)數(shù)不改變;對(duì)于不可變對(duì)象是淺復(fù)制, 引用計(jì)數(shù)每次加一竟稳。始終返回一個(gè)不可變對(duì)象属桦。

3.mutableCopy:始終是深復(fù)制,引用計(jì)數(shù)不改變他爸。始終返回一個(gè)可變對(duì)象聂宾。

下面把容器非容器,可變非可變結(jié)合著retain,copy,mutableCopy來仔細(xì)的分析一下OC中得深淺拷貝诊笤,代碼走起:

1.非容器 + 不可變對(duì)象 + retain + copy + mutableCopy

NSString *str = @"InteviewTestCode";

//把str通過copy的方式把值賦給str2

NSString *str2 = [str copy];

//把str通過mutableCopy的方式把值賦給str3

NSString *str3 = [str mutableCopy];


//分別輸出每個(gè)字符串的內(nèi)存地址

NSLog(@" str-p = %p", str);

NSLog(@"str2-p = %p", str2);

NSLog(@"str3-p = %p", str3);

代碼運(yùn)行結(jié)果分析:

2017-02-17 09:57:02.690 InteviewTestCode[18890:507384]  str-p = 0x10d185110

2017-02-17 09:57:02.690 InteviewTestCode[18890:507384] str2-p = 0x10d185110

2017-02-17 09:57:02.691 InteviewTestCode[18890:507384] str3-p = 0x60800006fd80

\1. 對(duì)于非容器類的不可變對(duì)象retain和copy為淺拷貝系谐,mutableCopy為深拷貝

淺拷貝獲得的對(duì)象的地址和原有對(duì)象的地址一致

3.而深拷貝返回新的內(nèi)存地址,并且返回的對(duì)象為可變對(duì)象

2.非容器 + 可變對(duì)象 + retain + copy + mutableCopy

接下來我們來測(cè)試下非容器類的可變對(duì)象的深淺拷貝

代碼如下:

Objective-C

//2.非容器 + 可變對(duì)象 + retain + copy + mutableCopy

NSMutableString *s = [NSMutableString stringWithFormat:@"InteviewTestCode"];

//把s通過copy的方式把值賦給s2;

NSMutableString *s2 = [s copy];

//把s通過mutableCopy的方式把值賦給s3

NSMutableString *s3 = [s mutableCopy];

?

//打印每個(gè)非容器類可變對(duì)象的地址

NSLog(@" s_p = %p", s);

NSLog(@"s2_p = %p", s2);

NSLog(@"s3_p = %p", s3);

?```

運(yùn)行結(jié)果分析:

InteviewTestCode[18890:507384] s_p = 0x600000071580

2017-02-17 09:57:02.692 InteviewTestCode[18890:507384] s2_p = 0xa6968736164756c7

2017-02-17 09:57:02.692 InteviewTestCode[18890:507384] s3_p = 0x600000071280

1.retian對(duì)對(duì)可變對(duì)象為淺拷貝

2.copy對(duì)可變對(duì)象非容器類為深拷貝

3.mutableCopy對(duì)可變非容器類為深拷貝

**3.容器類 +  非可變對(duì)象 + retain + copy + mutableCopy**

容器類的非可變對(duì)象進(jìn)行測(cè)試:容器需要特別注意的是容器本身和容器內(nèi)的對(duì)象分別是什么結(jié)果讨跟,(1)從容器對(duì)象看而言是容器的深拷貝, (2)但從輸出容器中的元素是容器的淺拷貝(所以下面代碼并不是容器真正意義上的的完全拷貝,本文最后做介紹)纪他。

NSMutableString *string = [NSMutableString stringWithFormat:@"ludashi"];

//第二種:容器類不可變對(duì)象拷貝

NSArray *array = [NSArray arrayWithObjects:string, @"b", nil];

?

//把a(bǔ)rray通過copy的方式把值賦給array2

NSArray *array2 = [array copy];

?

//把a(bǔ)rray通過mutableCopy方式把值賦給array3

NSArray *array3 = [array mutableCopy];

?

//分別輸出每個(gè)地址

NSLog(@"分別輸出每個(gè)地址");

NSLog(@" array_p = %p", array);

NSLog(@"array2_p = %p", array2);

NSLog(@"array3_p = %p", array3);

?

//分別輸出每個(gè)地址

NSLog(@"分別輸出拷貝后數(shù)組中第一個(gè)元素的地址");

NSLog(@" array_p[0] = %p", array[0]);

NSLog(@"array2_p[0] = %p", array2[0]);

NSLog(@"array3_p[0] = %p", array3[0]);

運(yùn)行結(jié)果:

2017-02-17 10:29:18.065 InteviewTestCode[18973:524282] 分別輸出每個(gè)地址

2017-02-17 10:29:18.065 InteviewTestCode[18973:524282] array_p = 0x608000036600

2017-02-17 10:29:18.065 InteviewTestCode[18973:524282] array2_p = 0x608000036600

2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] array3_p = 0x6080000498d0

2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] 分別輸出拷貝后數(shù)組中第一個(gè)元素的地址

2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] array_p[0] = 0x608000074340

2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] array2_p[0] = 0x608000074340

2017-02-17 10:29:18.078 InteviewTestCode[18973:524282] array3_p[0] = 0x608000074340

容器類的非可變對(duì)象:

copy拷貝獲得的對(duì)象的地址和原有對(duì)象的地址一致

2.而mutableCopy拷貝返回新的內(nèi)存地址,并且返回的對(duì)象為可變對(duì)象

3.而容器內(nèi)對(duì)象的地址總是一樣的,不受copy,mutableCopy影響

**4.容器類 +  可變對(duì)象 + retain + copy + mutableCopy**

下面對(duì)容器類的可變對(duì)象進(jìn)行測(cè)試晾匠,copy和mutableCopy對(duì)于容器本身是深拷貝茶袒,原因是返回了一個(gè)新的容器地址,但對(duì)于容器中的元素仍然是淺拷貝混聊。

代碼如下:

//第四種:容器類的可變對(duì)象的拷貝弹谁,用NSMutableArray來實(shí)現(xiàn)

NSMutableArray *m_array = [NSMutableArray arrayWithObjects:string, nil];

NSMutableArray *m_array2 = [m_array copy];

//把m_array通過mytableCopy把值賦給m_array3

NSMutableArray *m_array3 = [m_array mutableCopy];

?

//打印輸出每個(gè)可變?nèi)萜鲗?duì)象的地址

NSLog(@"打印輸出每個(gè)可變?nèi)萜鲗?duì)象的地址");

NSLog(@" m_array_p = %p", m_array);

NSLog(@"m_array_p2 = %p", m_array2);

NSLog(@"m_array_p3 = %p", m_array3);

?

//打印輸出每個(gè)可變?nèi)萜髦性氐牡刂?/p>

NSLog(@"打印輸出每個(gè)可變?nèi)萜髦性氐牡刂?);

NSLog(@" m_array_p[0] = %p", m_array[0]);

NSLog(@"m_array_p2[0] = %p", m_array2[0]);

NSLog(@"m_array_p3[0] = %p", m_array3[0]);

運(yùn)行結(jié)果:

2017-02-17 10:29:18.078 InteviewTestCode[18973:524282] 打印輸出每個(gè)可變?nèi)萜鲗?duì)象的地址

2017-02-17 10:29:18.078 InteviewTestCode[18973:524282] m_array_p = 0x608000049780

2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] m_array_p2 = 0x60800001a0a0

2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] m_array_p3 = 0x608000049300

2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] 打印輸出每個(gè)可變?nèi)萜髦性氐牡刂?/p>

2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] m_array_p[0] = 0x608000074340

2017-02-17 10:29:18.080 InteviewTestCode[18973:524282] m_array_p2[0] = 0x608000074340

2017-02-17 10:29:18.080 InteviewTestCode[18973:524282] m_array_p3[0] = 0x608000074340

容器類的可變對(duì)象:

1.copy:對(duì)于可變對(duì)象為深復(fù)制,引用計(jì)數(shù)不改變;對(duì)于不可變對(duì)象是淺復(fù)制句喜, 引用計(jì)數(shù)每次加一。始終返回一個(gè)不可變對(duì)象沟于。

2.mutableCopy:始終是深復(fù)制咳胃,引用計(jì)數(shù)不改變。始終返回一個(gè)可變對(duì)象旷太。

**5.自定義類對(duì)象之間的深淺拷貝問題**

在Objective-C中并不是所有的類都支持拷貝展懈;只有遵循NSCopying協(xié)議的類销睁,才支持copy拷貝,只有遵循NSMutableCopying協(xié)議的類存崖,才支持mutableCopy拷貝冻记。如果沒有遵循拷貝協(xié)議,拷貝時(shí)會(huì)出錯(cuò)来惧。

如果我們想再我們自定義的類中支持copy和mutableCopy那么我們就需要使我們定義的類遵循NSCopying和NSMutableCopying協(xié)議冗栗,代碼如下:

@interface CopyTestObj : NSObject<NSCopying,NSMutableCopying>

@end

然后再重寫-(id) copyWithZone : (NSZone *) zone  和 -(id)mutableCopyWithZone : (NSZone *) zone

重寫-(id) copyWithZone :(NSZone *)zone方法如下

//淺拷貝

-(id) copyWithZone:(NSZone *) zone {

CopyTestObj *test = [[CopyTestObj allocWithZone : zone] init];

return test;

}

//深拷貝

-(id) mutableCopyWithZone : (NSZone *) zone {

CopyTestObj *test = [[CopyTestObj allocWithZone : zone] init];

//區(qū)別:對(duì)屬性也進(jìn)行復(fù)制

test.typeStr = self.typeStr;

return test;

}

6.我們?nèi)绾螌?shí)現(xiàn)容器中的完全拷貝呢?上面沒有考慮到容器中元素拷貝的問題供搀,下面進(jìn)行代碼補(bǔ)充

首先:遵循NSCoder協(xié)議

@interface CopyTestObj : NSCoder<NSCopying,NSMutableCopying>

代碼如下:

//新建一個(gè)測(cè)試字符串

NSMutableString * str = [NSMutableString stringWithFormat:@"ludashi__"];

//新建一個(gè)測(cè)試字典

NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:1];

[dic setObject:str forKey:@"key1"];

?

//把字典存入數(shù)組中

NSMutableArray *oldArray = [NSMutableArray arrayWithObject:dic];

?

//用就得數(shù)組生成新的數(shù)組

NSMutableArray *newArray = [NSMutableArray arrayWithArray:oldArray];

?

//用copyItems拷貝數(shù)組中的元素

NSMutableArray *copyItems = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES];

?

//把數(shù)組歸檔成一個(gè)NSData,然后再實(shí)現(xiàn)完全拷貝

NSData * data = [NSKeyedArchiver archivedDataWithRootObject:oldArray];

NSMutableArray *multable = [NSKeyedUnarchiver unarchiveObjectWithData:data];

?

//往字典中加入新的值

[dic setObject:@"new_value1" forKey:@"key2"];

//改變str的值

[str appendString:@"update"];

NSLog(@"%@", oldArray);

NSLog(@"%@", newArray);

NSLog(@"%@", copyItems);

NSLog(@"%@", multable);

?

//每個(gè)數(shù)組的地址為:

NSLog(@"%p", oldArray);

NSLog(@"%p", newArray);

NSLog(@"%p", copyItems);

NSLog(@"%p", multable);

運(yùn)行結(jié)果:

2014-08-13 16:33:00.752 OC6-1[3942:303] (

{

key1 = "ludashi__update";

key2 = "new_value1";

}

)

2014-08-13 16:33:00.753 OC6-1[3942:303] (

{

key1 = "ludashi__update";

key2 = "new_value1";

}

)

2014-08-13 16:33:00.753 OC6-1[3942:303] (

{

key1 = "ludashi__update";

}

)

2014-08-13 16:33:00.753 OC6-1[3942:303] (

{

key1 = "ludashi__";

}

)

2014-08-13 16:33:00.754 OC6-1[3942:303] 0x100204560

2014-08-13 16:33:00.754 OC6-1[3942:303] 0x1002046d0

2014-08-13 16:33:00.754 OC6-1[3942:303] 0x1002047c0

2014-08-13 16:33:00.755 OC6-1[3942:303] 0x100406610

可以看出,通過數(shù)組歸檔可以實(shí)現(xiàn)容器深復(fù)制 和 容器里的 對(duì)象 也同時(shí)深復(fù)制(地址不同)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隅居,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子葛虐,更是在濱河造成了極大的恐慌胎源,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屿脐,死亡現(xiàn)場(chǎng)離奇詭異涕蚤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)的诵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門万栅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奢驯,你說我怎么就攤上這事申钩。” “怎么了瘪阁?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵撒遣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我管跺,道長(zhǎng)义黎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任豁跑,我火速辦了婚禮廉涕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艇拍。我一直安慰自己狐蜕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布卸夕。 她就那樣靜靜地躺著层释,像睡著了一般。 火紅的嫁衣襯著肌膚如雪快集。 梳的紋絲不亂的頭發(fā)上贡羔,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天廉白,我揣著相機(jī)與錄音,去河邊找鬼乖寒。 笑死猴蹂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的楣嘁。 我是一名探鬼主播磅轻,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼马澈!你這毒婦竟也來了瓢省?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤痊班,失蹤者是張志新(化名)和其女友劉穎勤婚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涤伐,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馒胆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凝果。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祝迂。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖器净,靈堂內(nèi)的尸體忽然破棺而出型雳,到底是詐尸還是另有隱情,我是刑警寧澤山害,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布纠俭,位于F島的核電站,受9級(jí)特大地震影響浪慌,放射性物質(zhì)發(fā)生泄漏冤荆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一权纤、第九天 我趴在偏房一處隱蔽的房頂上張望钓简。 院中可真熱鬧,春花似錦汹想、人聲如沸外邓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坐榆。三九已至,卻和暖如春冗茸,著一層夾襖步出監(jiān)牢的瞬間席镀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工夏漱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豪诲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓挂绰,卻偏偏與公主長(zhǎng)得像屎篱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子葵蒂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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

  • 1交播、對(duì)象拷貝有兩種方式:淺復(fù)制和深復(fù)制。顧名思義践付,淺復(fù)制秦士,并不拷貝對(duì)象本身,僅僅是拷貝指向?qū)ο蟮闹羔樣栏撸簧顝?fù)制是直接...
    滴答大閱讀 772評(píng)論 0 2
  • 深拷貝和淺拷貝這個(gè)問題在面試中常常被問到隧土,而在實(shí)際開發(fā)中,只要稍有不慎命爬,就會(huì)在這里出現(xiàn)問題曹傀。尤其對(duì)于初學(xué)者來說,我...
    西門淋雨閱讀 1,786評(píng)論 0 1
  • IOS開發(fā)之深拷貝與淺拷貝(mutableCopy與Copy)詳解 copy與retain的區(qū)別: copy是創(chuàng)建...
    第六夢(mèng)閱讀 472評(píng)論 0 1
  • 淺拷貝就是拷貝后饲宛,并沒有進(jìn)行真正的復(fù)制皆愉,而是復(fù)制的對(duì)象和原對(duì)象都指向同一個(gè)地址 深拷貝是真正的復(fù)制了一份,復(fù)制的對(duì)...
    dpplh閱讀 24,362評(píng)論 21 74
  • 簡(jiǎn)述深淺拷貝 我們實(shí)例化的對(duì)象存儲(chǔ)在堆區(qū),而指向?qū)ο蟮闹羔樢话愦鎯?chǔ)在棧區(qū)练链。我們需要知道這個(gè)前提翔脱。??實(shí)際上拷貝分為...
    刀客傳奇閱讀 4,867評(píng)論 11 6