iOS 談?wù)刢opy和mutableCopy

copy 是淺拷貝状知,mutableCopy 是深拷貝,從我學(xué)習(xí)的時(shí)候開(kāi)始 老師貌似也是這么說(shuō)的孽查,我也一直是這么記的【尷尬】這是不對(duì)的<病!Cぴ佟N魃琛!4鹋蟆4俊!B逃场擒滑!

創(chuàng)建一個(gè)對(duì)象, 該對(duì)象與源對(duì)象的內(nèi)容一致,此時(shí)使用copy與mutableCopy的區(qū)別:
copy拷貝出來(lái)的對(duì)象類型總是不可變類型(例如, NSString, NSDictionary, NSArray等等)
mutableCopy拷貝出來(lái)的對(duì)象類型總是可變類型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)

聲明屬性的時(shí)候修飾使用copy修飾的原因:
補(bǔ)充一點(diǎn)堆棧的介紹:
堆和棧是操作系統(tǒng)的內(nèi)存中堆和棧,不是數(shù)據(jù)結(jié)構(gòu)中的堆和棧叉弦。
1丐一、堆(heap)區(qū):堆是由程序員分配和釋放,用于存放進(jìn)程運(yùn)行中被動(dòng)態(tài)分配的內(nèi)存段淹冰,它大小并不固定库车,可動(dòng)態(tài)擴(kuò)張或縮減。當(dāng)進(jìn)程調(diào)用alloc等函數(shù)分配內(nèi)存時(shí)樱拴,新分配的內(nèi)存就被動(dòng)態(tài)添加到堆上(堆被擴(kuò)張)柠衍;當(dāng)利用realse釋放內(nèi)存時(shí),被釋放的內(nèi)存從堆中被剔除(堆被縮減)晶乔,因?yàn)槲覀儸F(xiàn)在iOS基本都使用ARC來(lái)管理對(duì)象珍坊,所以不用我們程序員來(lái)管理,但是我們要知道這個(gè)對(duì)象存儲(chǔ)的位置正罢。
2阵漏、棧(stack)區(qū):棧是由編譯器自動(dòng)分配并釋放默刚,用戶存放程序臨時(shí)創(chuàng)建的局部變量好渠,存放函數(shù)的參數(shù)值,局部變量等拼窥。也就是說(shuō)我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量裆泳,static意味這在數(shù)據(jù)段中存放變量)叹洲。除此以外在函數(shù)被調(diào)用時(shí),其參數(shù)也會(huì)被壓入發(fā)起調(diào)用的進(jìn)程棧中工禾,并且待到調(diào)用結(jié)束后运提,函數(shù)的返回值也回被存放回棧中蝗柔。由于棧的先進(jìn)后出特點(diǎn),所以棧特別方便用來(lái)保存/恢復(fù)調(diào)用現(xiàn)場(chǎng)民泵。從這個(gè)意義上將我們可以把椊朐郏看成一個(gè)臨時(shí)數(shù)據(jù)寄存、交換的內(nèi)存區(qū)洪灯。

  • block為什么要用copy?
    MRC下不使用copy修飾, block存儲(chǔ)在棧區(qū), 作用域結(jié)束, block這個(gè)局部變量被銷(xiāo)毀, 而一個(gè)strong指針還指向了這個(gè)被回收的地址.所以使用copy,把block拷貝到堆區(qū), 并且指向堆區(qū)的block. 但是在ARC下無(wú)論copy,還是stong都無(wú)所謂, 因?yàn)橄到y(tǒng)已經(jīng)在創(chuàng)建block的時(shí)候, 已經(jīng)拷貝到堆區(qū)了。copy在MRC中是為了保護(hù)block的封裝性將其移動(dòng)至堆區(qū)竟痰。但在ARC中更多的是為了語(yǔ)義化签钩、因?yàn)橄到y(tǒng)自動(dòng)幫你移動(dòng)了

補(bǔ)充個(gè)常用的NSString用copy修飾的原因:
用copy是為了安全,防止NSMutableString賦值給NSString時(shí),前者修改引起后者值變化而用的.這個(gè)也適用于別的下文也會(huì)提到并驗(yàn)證。

@property (nonatomic,strong) NSString *myName;
NSMutableString *mStr = [[NSMutableString alloc] initWithString:@"daLi"];
    self.myName = mStr;
    NSLog(@"%@", self.myName);
    [mStr appendString:@"好美"];
    NSLog(@"%@", mStr);
    NSLog(@"%@", self.myName);
    /*
     分析:self.myName聲明的時(shí)候使用strong修飾坏快,會(huì)跟著mStr的改變而改變
     輸出:
     2017-12-11 16:41:39.146126+0800 Demo[20438:1163039] daLi
     2017-12-11 16:41:39.146357+0800 Demo[20438:1163039] daLi好美
     2017-12-11 16:41:39.146496+0800 Demo[20438:1163039] daLi好美
     */
@property (nonatomic,copy) NSString *myName;
NSMutableString *mStr = [[NSMutableString alloc] initWithString:@"daLi"];
    self.myName = mStr;
    NSLog(@"%@", self.myName);
    [mStr appendString:@"好美"];
    NSLog(@"%@", mStr);
    NSLog(@"%@", self.myName);
    /*
     分析:self.myName聲明的時(shí)候使用copy修飾铅檩,不會(huì)跟著mStr的改變而改變
     輸出:
     2017-12-11 16:46:08.367018+0800 Demo[20507:1166962] daLi
     2017-12-11 16:46:08.367227+0800 Demo[20507:1166962] daLi好美
     2017-12-11 16:46:08.367353+0800 Demo[20507:1166962] daLi
     */

淺拷貝和深拷貝的分析
先介紹一下什么是iOS里面的系統(tǒng)容器類:
比如NSArray,NSMutableArray莽鸿,NSDictionary昧旨,NSMutableDictionary....
淺拷貝和深拷貝?祥得?兔沃??级及?英文就是shallow copy和deep copy

  • 淺拷貝:正常的拷貝乒疏,生成一個(gè)新的容器,但卻是和原來(lái)的容器共用內(nèi)部的元素饮焦;
  • 深拷貝:不僅生成新的容器怕吴,還生成了新的內(nèi)部元素。

稍作總結(jié):淺拷貝復(fù)制容器县踢,深拷貝復(fù)制容器及其內(nèi)部元素
(copy 與 mutableCopy 不等同于淺拷貝與深拷貝)
接下來(lái)用代碼驗(yàn)證這些:

NSMutableArray *mArr = [NSMutableArray arrayWithObject:@1];
    NSLog(@"1-%@--%p", mArr, mArr);
    NSMutableArray *marr0 = [NSMutableArray arrayWithObject:mArr];
    NSLog(@"2-%@--%p--%p", marr0, marr0, marr0[0]);
    NSMutableArray *mCopyArr = [marr0 mutableCopy];//替換成copy是一樣的效果
    NSLog(@"3-%@--%p--%p", mCopyArr, mCopyArr, mCopyArr[0]);
    [mCopyArr[0] addObject:@2];
    NSLog(@"4-%@--%p--%p", mCopyArr, mCopyArr, mCopyArr[0]);
    NSLog(@"5-%@--%p--%p", marr0, marr0, marr0[0]);
    [marr0[0] addObject:@3];
    NSLog(@"6-%@--%p--%p", mCopyArr, mCopyArr, mCopyArr[0]);
    NSLog(@"7-%@--%p--%p", marr0, marr0, marr0[0]);
/*
 修改了mCopyArr的元素转绷,marr0也跟著改變了元素,因?yàn)槎叩脑厥枪灿玫呐鹌。琜marr0 mutableCopy]只拷貝了數(shù)組容器议经,里面的元素并沒(méi)有拷貝,而是和marr0共用的元素,所以marr0[0]丙曙、mCopyArr[0]元素的地址是一個(gè)爸业,無(wú)論修改它們倆哪一個(gè),對(duì)應(yīng)的數(shù)組marr0亏镰、mCopyArr里面的元素都會(huì)跟著改變扯旷。
 由此驗(yàn)證出來(lái):容器類的mutableCopy和copy是淺拷貝,只拷貝容器索抓,并不拷貝元素>觥毯炮!
 輸出結(jié)果:
 2017-12-11 14:41:53.551658+0800 Demo[19619:1091522] 1-(
 1
 )--0x600000059f50
 2017-12-11 14:41:53.551876+0800 Demo[19619:1091522] 2-(
 (
 1
 )
 )--0x6000002576a0--0x600000059f50
 2017-12-11 14:41:53.552080+0800 Demo[19619:1091522] 3-(
 (
 1
 )
 )--0x60000000b9f0--0x600000059f50
 2017-12-11 14:41:53.552357+0800 Demo[19619:1091522] 4-(
 (
 1,
 2
 )
 )--0x60000000b9f0--0x600000059f50
 2017-12-11 14:41:53.552545+0800 Demo[19619:1091522] 5-(
 (
 1,
 2
 )
 )--0x6000002576a0--0x600000059f50
 2017-12-11 14:41:53.552687+0800 Demo[19619:1091522] 6-(
 (
 1,
 2,
 3
 )
 )--0x60000000b9f0--0x600000059f50
 2017-12-11 14:41:53.552806+0800 Demo[19619:1091522] 7-(
 (
 1,
 2,
 3
 )
 )--0x6000002576a0--0x600000059f50
 */

寫(xiě)一個(gè)NSArray驗(yàn)證一下

NSArray *arr = @[@"1"];
    NSLog(@"1-%@--%p", arr, arr);
    NSArray *arr0 = arr;
    NSLog(@"2-%@--%p", arr0, arr0);
    NSArray *arr1 = [arr copy];
    NSLog(@"3-%@--%p", arr1, arr1);
    NSArray *arr2 = [arr mutableCopy];
    NSLog(@"4-%@--%p", arr2, arr2);
    arr = @[@"2"];
    NSLog(@"5-%@--%p", arr, arr);
    NSLog(@"6-%@--%p", arr0, arr0);
    NSLog(@"7-%@--%p", arr1, arr1);
    NSLog(@"8-%@--%p", arr2, arr2);
    /*
     分析:
     arr初始化指向的是@[@"1"]數(shù)組,
     1耸黑、arr0是直接用arr賦值的桃煎,都是指向了@[@"1"],當(dāng)arr = @[@"2"]大刊,arr指向了@[@"2"]這個(gè)數(shù)組为迈,而arr0不變,因?yàn)閍rr0依舊指向的是@[@"1"]缺菌;
     2葫辐、arr1,[arr copy]伴郁,使得arr1指向了arr指向的@[@"1"]耿战,后面arr的指向改變并不會(huì)導(dǎo)致arr1的指向改變;
     3焊傅、arr2剂陡,[arr mutableCopy],使得arr1指向了arr指向的@[@"1"]狐胎,后面arr的指向改變并不會(huì)導(dǎo)致arr1的指向改變鸭栖;
     輸出:
     2017-12-11 15:12:21.130514+0800 Demo[19697:1107933] 1-(
     1
     )--0x600000001c20
     2017-12-11 15:12:21.130690+0800 Demo[19697:1107933] 2-(
     1
     )--0x600000001c20
     2017-12-11 15:12:21.130835+0800 Demo[19697:1107933] 3-(
     1
     )--0x600000001c20
     2017-12-11 15:12:21.130994+0800 Demo[19697:1107933] 4-(
     1
     )--0x604000056770
     2017-12-11 15:12:21.131122+0800 Demo[19697:1107933] 5-(
     2
     )--0x604000002380
     2017-12-11 15:12:21.131255+0800 Demo[19697:1107933] 6-(
     1
     )--0x600000001c20
     2017-12-11 15:12:21.131342+0800 Demo[19697:1107933] 7-(
     1
     )--0x600000001c20
     2017-12-11 15:12:21.131431+0800 Demo[19697:1107933] 8-(
     1
     )--0x604000056770
     */

cpoy 與直接賦值的對(duì)比分析

直接賦值:
    NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@"1", nil];
    NSLog(@"0-%@--%p", mArr, mArr);
    NSArray *arr = mArr;
    NSLog(@"1-%@--%p", arr, arr);
    [mArr addObject:@"2"];
    NSLog(@"2-%@--%p", mArr, mArr);
    NSLog(@"3-%@--%p", arr, arr);
/*
 分析:使用直接賦值的方式給arr=mArr,可變數(shù)組mArr添加對(duì)象是在賦值之后, 為什么后面添加對(duì)象還會(huì)影響到不可變數(shù)組arr呢?? 原因很簡(jiǎn)單, 因?yàn)镺bjective-C支持多態(tài). 所以表面上arr是NSArray對(duì)象, 其實(shí)骨子里是NSMutableArray對(duì)象.這樣的話將會(huì)對(duì)后期DEBUG增加很大的成本, 可能會(huì)導(dǎo)致莫名其妙的錯(cuò)誤.開(kāi)發(fā)過(guò)程中應(yīng)該注意此類情況
 輸出:
 2017-12-11 15:46:21.532252+0800 Demo[20106:1129830] 0-(
 1
 )--0x604000441350
 2017-12-11 15:46:21.532407+0800 Demo[20106:1129830] 1-(
 1
 )--0x604000441350
 2017-12-11 15:46:21.532528+0800 Demo[20106:1129830] 2-(
 1,
 2
 )--0x604000441350
 2017-12-11 15:46:21.532652+0800 Demo[20106:1129830] 3-(
 1,
 2
 )--0x604000441350
 */
copy/mutableCopy:
NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@"1", nil];
    NSLog(@"0-%@--%p", mArr, mArr);
    NSArray *arr = [mArr copy];//mutableCopy
    NSLog(@"1-%@--%p", arr, arr);
    [mArr addObject:@"2"];
    NSLog(@"2-%@--%p", mArr, mArr);
    NSLog(@"3-%@--%p", arr, arr);
/*
 分析:arr使用copy獲取之后顽爹,再次修改mArr不會(huì)造成arr的改變纤泵,保障了arr的安全。
 輸出:
 2017-12-11 15:51:29.749360+0800 Demo[20137:1133165] 0-(
 1
 )--0x60000005daf0
 2017-12-11 15:51:29.749537+0800 Demo[20137:1133165] 1-(
 1
 )--0x600000007ec0
 2017-12-11 15:51:29.749639+0800 Demo[20137:1133165] 2-(
 1,
 2
 )--0x60000005daf0
 2017-12-11 15:51:29.749787+0800 Demo[20137:1133165] 3-(
 1
 )--0x600000007ec0
 */

然后再寫(xiě)一個(gè)字典的來(lái)驗(yàn)證驗(yàn)證:

NSDictionary *dictA = @{@"a": @"a"};
    NSDictionary *dictB = dictA;
    dictA = @{@"b": @"b"};
    NSLog(@"%@ - %p",dictA, dictA); // {b = b}
    NSLog(@"%@ - %p",dictB, dictB); // {a = a}
    
    /*
     dictB = dictA, 代表dictA和dictB都指向{@"a" : @"a"},
     dictA = @{@"b" : @"b"}這行代碼之后dictA就轉(zhuǎn)而指向@{@"b" : @"b"}了.
     而dictA仍然指向{@"a" : @"a"}.
     所以輸出:
     {
     b = b;
     } - 0x604000039ae0
     {
     a = a;
     } - 0x604000030180
     */
    
    Person *pA = [[Person alloc] init];
    pA.name = @"A1";
    Person *pB = [[Person alloc] init];
    pB = pA;
    pA.name = @"A2";
    NSLog(@"%@ - %p - %p", pA.name, pA, &pA);
    NSLog(@"%@ - %p - %p", pB.name, pB, &pB);
    /*
      Person *pB = [[Person alloc] init];這句代碼是沒(méi)有任何作用的, 對(duì)pB后面的指向沒(méi)有任何影響, pB = pA這句代碼過(guò)后, pB和pA指向的是同一個(gè)對(duì)象, 那么通過(guò)pA修改其指向的對(duì)象的name屬性, 自然也會(huì)影響到pB指向的對(duì)象的name屬性. 因?yàn)樗麄儍蓚€(gè)指向的是同一個(gè)對(duì)象
     A2 - 0x600000017a50 - 0x7fff5c47cb40
     A2 - 0x600000017a50 - 0x7fff5c47cb38
     */
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末镜粤,一起剝皮案震驚了整個(gè)濱河市捏题,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肉渴,老刑警劉巖公荧,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異同规,居然都是意外死亡循狰,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)券勺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绪钥,“玉大人,你說(shuō)我怎么就攤上這事关炼〕谈梗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵儒拂,是天一觀的道長(zhǎng)寸潦。 經(jīng)常有香客問(wèn)我色鸳,道長(zhǎng),這世上最難降的妖魔是什么见转? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任命雀,我火速辦了婚禮,結(jié)果婚禮上斩箫,老公的妹妹穿的比我還像新娘吏砂。我一直安慰自己,他們只是感情好乘客,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布赊抖。 她就那樣靜靜地躺著,像睡著了一般寨典。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上房匆,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天耸成,我揣著相機(jī)與錄音,去河邊找鬼浴鸿。 笑死井氢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岳链。 我是一名探鬼主播花竞,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掸哑!你這毒婦竟也來(lái)了约急?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤苗分,失蹤者是張志新(化名)和其女友劉穎厌蔽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體摔癣,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奴饮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了择浊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戴卜。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖琢岩,靈堂內(nèi)的尸體忽然破棺而出投剥,到底是詐尸還是另有隱情,我是刑警寧澤粘捎,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布薇缅,位于F島的核電站危彩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泳桦。R本人自食惡果不足惜汤徽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灸撰。 院中可真熱鬧谒府,春花似錦、人聲如沸浮毯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)债蓝。三九已至壳鹤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饰迹,已是汗流浹背芳誓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啊鸭,地道東北人锹淌。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赠制,于是被迫代替她去往敵國(guó)和親赂摆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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

  • 前言 不敢說(shuō)覆蓋OC中所有copy的知識(shí)點(diǎn)钟些,但最起碼是目前最全的最新的一篇關(guān)于 copy的技術(shù)文檔了烟号。后續(xù)發(fā)現(xiàn)有新...
    zyydeveloper閱讀 3,358評(píng)論 4 35
  • 本文為轉(zhuǎn)載: 作者:zyydeveloper 鏈接:http://www.reibang.com/p/5f776a...
    Buddha_like閱讀 873評(píng)論 0 2
  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,140評(píng)論 30 470
  • 設(shè)計(jì)模式是什么? 你知道哪些設(shè)計(jì)模式政恍,并簡(jiǎn)要敘述褥符?設(shè)計(jì)模式是一種編碼經(jīng)驗(yàn),就是用比較成熟的邏輯去處理某一種類型的事...
    irenb閱讀 5,212評(píng)論 1 21
  • 仰觀歷史星河,李白這位大詩(shī)人恐怕是浩瀚的詩(shī)詞星座中最為明亮的星了鹤树。一首《靜夜思》讓彼時(shí)尚在懵懂年紀(jì)的我記住了這位詩(shī)...
    劉皮皮有點(diǎn)皮閱讀 1,573評(píng)論 4 35