iOS開(kāi)發(fā)中copy和mutableCopy賦值方法的異同

本文邏輯圖

本文邏輯圖

copy和mutableCopy賦值的異同
1.copy,mutableCopy都是深拷貝,也就是會(huì)重新開(kāi)辟出一塊內(nèi)存來(lái)保存和原有值相同的值,原有值的變化不會(huì)修改被賦值對(duì)象的值。
2.copy的被賦值對(duì)象不可被修改,mutableCopy得到的對(duì)象可被修改。且不受原值和接受值的類型影響。
3.容器對(duì)象(數(shù)組)中的元素是淺拷貝,修改后依舊會(huì)對(duì)被賦值對(duì)象造成影響。
下面我們依次通過(guò)非容器變量和容器變量來(lái)驗(yàn)證上面三條。

1.copy,mutableCopy都是深拷貝,也就是會(huì)重新開(kāi)辟出一塊內(nèi)存來(lái)保存和原有值相同的值,原有值的變化不會(huì)修改被賦值對(duì)象的值

初始化一個(gè)mStrOrigin,通過(guò)copy方法賦值給mStrFromCopy,mStrFromMCopy,輸出三者的值和地址。觀察他們的值和地址是否相同,從而判斷是copy和mutableCopy是否深拷貝。

NSMutableString *mStrOrigin = [[NSMutableString alloc] initWithString:@"mStr"];
NSMutableString *mStrFromCopy = [mStrOrigin copy];
NSMutableString *mStrFromMCopy = [mStrOrigin mutableCopy];
NSLog(@"值:mStrOrigin:%@ mStrFromCopy:%@  mStrFromMCopy:%@ \n  地址:mStrOrigin:%p mStrFromCopy:%p  mStrFromMCopy:%p \n",mStrOrigin,mStrFromCopy,mStrFromMCopy,mStrOrigin,mStrFromCopy,mStrFromMCopy);

有輸出

值:mStrOrigin:mStr mStrFromCopy:mStr  mStrFromMCopy:mStr
地址:mStrOrigin:0x7fec40c5bd00 mStrFromCopy:0xa0000007274536d4  mStrFromMCopy:0x7fec40c59c00

現(xiàn)象:mStrOrigin,mStrFromCopy,mStrFromMCopy三者地址都不一樣
結(jié)論:copy和mutableCopy是深拷貝

我們修改原值mStrOrigin 觀察mStrFromCopy,mStrFromMCopy是否會(huì)隨之變化

[mStrOrigin appendString:@"-change1"];
NSLog(@"值:mStrOrigin:%@ mStrFromCopy:%@  mStrFromMCopy:%@ \n  地址:mStrOrigin:%p mStrFromCopy:%p  mStrFromMCopy:%p \n",mStrOrigin,mStrFromCopy,mStrFromMCopy,mStrOrigin,mStrFromCopy,mStrFromMCopy);

有輸出

值:mStrOrigin:mStr-change1 mStrFromCopy:mStr  mStrFromMCopy:mStr
地址:mStrOrigin:0x7fec40c5bd00 mStrFromCopy:0xa0000007274536d4  mStrFromMCopy:0x7fec40c59c00

現(xiàn)象:隨著mStrOrigin變化,mStrFromMCopy和mStrFromMCopy均沒(méi)有隨之變化
結(jié)論:copy和mutableCopy出來(lái)的是新的內(nèi)存,原值改變新的值不改變。
他們的賦值結(jié)構(gòu)圖如下:

copy,mutableCopy賦值示意圖1

2.copy的被賦值對(duì)象不可被修改,mutableCopy得到的對(duì)象可被修改。且不受原值和接受值的類型影響。

嘗試修改mStrFromCopy(由copy方法得到),查看是否會(huì)崩潰,從而判斷copy出來(lái)的對(duì)象不可被修改的

NSMutableArray   *mArrOrigin = [[NSMutableArray alloc] init];
NSMutableString  *mstr1 = [[NSMutableString alloc] initWithString:@"value1"];
NSMutableString  *mstr2 = [[NSMutableString alloc] initWithString:@"value2"];
NSMutableString *mStrOrigin = [[NSMutableString alloc] initWithString:@"mStr"];
[mArrOrigin addObject:mstr1];
[mArrOrigin addObject:mstr2];
NSMutableArray *mArrFromCopy = [mArrOrigin copy];
NSMutableString *mStrFromCopy = [mStrOrigin copy];

[mStrFromCopy appendString:@"-change3"]; //崩潰 'Attempt to mutate immutable object with appendString:'
[mArrFromMCopy addObject:mstr3];

現(xiàn)象:數(shù)組和字符串操作均發(fā)生崩潰
結(jié)論:copy出來(lái)的內(nèi)存是不可被修改的,就算你使用可變變量指針去接受,也不能被修改

嘗試修改mStrFromMCopy和mArrFromCopy(由mutablecopy得到),查看是否會(huì)奔潰

NSMutableString *mStrFromMCopy = [mStrOrigin mutableCopy];
NSMutableArray *mArrFromMCopy = [mArrOrigin mutableCopy];
[mStrFromMCopy appendString:@"-change4"];
[mArrFromMCopy addObject:mstr3];
NSLog(@"%@ %@",mStrFromMCopy,mArrFromMCopy);

現(xiàn)象:修改成功
結(jié)論:mutableCopy出來(lái)的數(shù)據(jù)地址可被修改

既然可以修改,如果我們用不可變量指針接受mutableCopy值,那內(nèi)存地址還能修改嗎?
我們?cè)囼?yàn)下,此處用可變變量mStrFromMCopy2弱引用指向mutableCopy的數(shù)據(jù)地址,嘗試修改mStrFromMCopy2并輸出三者 查看是否能修改成功。

NSString *strFromMCopy = [mStrOrigin mutableCopy];
NSMutableString *mStrFromMCopy2 = strFromMCopy;
//輸出地址,證明此時(shí)mStrFromMCopy2和strFromMCopy指向同一個(gè)數(shù)據(jù)內(nèi)存地址
NSLog(@"值:strFromMCopy:%@  mStrFromMCopy2:%@ 地址:strFromMCopy:%p mStrFromMCopy2:%p",strFromMCopy,mStrFromMCopy2,strFromMCopy,mStrFromMCopy2);
[mStrFromMCopy2 appendString:@"-change5"];
NSLog(@"值:strFromMCopy:%@  mStrFromMCopy2:%@ 地址:strFromMCopy:%p mStrFromMCopy2:%p",strFromMCopy,mStrFromMCopy2,strFromMCopy,mStrFromMCopy2);

現(xiàn)象:修改mStrFromMCopy2成功
結(jié)論:mutableCopy出來(lái)的數(shù)據(jù)地址可被修改,就算接受指針是不可變類型。此處還說(shuō)明一個(gè)問(wèn)題,即指針可以指向不同類型的數(shù)據(jù)內(nèi)存

剛才試驗(yàn)發(fā)現(xiàn)【原值是可變對(duì)象,用不可變類型的指針去獲取mutableCopy得到的值,發(fā)現(xiàn)數(shù)據(jù)地址可被修改】
那如果原值本身就不可修改,那mutableCopy后的被賦值對(duì)象是否也可修改。

//創(chuàng)建不可變對(duì)象
NSString *strOrigin = [[NSString alloc] initWithUTF8String:"string 1"];
mStrFromMCopy = [strOrigin mutableCopy];
[mStrFromMCopy appendString:@"-change6"];
NSLog(@"值:strOrigin %@,mStrFromMCopy %@",strOrigin,mStrFromMCopy);

輸出

值:strOrigin string 1,mStrFromMCopy string 1-change6

現(xiàn)象:修改mStrFromMCopy成功
結(jié)論:mutableCopy出來(lái)的數(shù)據(jù)地址可被修改,就算原值是不可變類型

3.容器變量中元素均是淺拷貝

創(chuàng)建一個(gè)可變?nèi)萜鱩ArrOrigin,初始化添加value1,value2兩個(gè)元素。并通過(guò)copy和mutableCopy賦值給mArrFromCopy,mArrFromMCopy。為原值增加一個(gè)元素value3,輸出三者地址和值。查看地址和值觀察是否是深拷貝

NSMutableArray   *mArrOrigin = [[NSMutableArray alloc] init];
NSMutableString  *mstr1 = [[NSMutableString alloc] initWithString:@"value1"];
NSMutableString  *mstr2 = [[NSMutableString alloc] initWithString:@"value2"];
NSMutableString  *mstr3 = [[NSMutableString alloc] initWithString:@"value3"];
[mArrOrigin addObject:mstr1];
[mArrOrigin addObject:mstr2];
NSMutableArray *mArrFromCopy = [mArrOrigin copy];
NSMutableArray *mArrFromMCopy = [mArrOrigin mutableCopy];
[mArrOrigin addObject:mstr3];
NSLog(@"值:mArrOrigin :%@ mArrFromCopy:%@ mArrFromMCopy%@\n  地址:mArrOrigin :%p\n mArrFromCopy:%p\n mArrFromMCopy:%p\n",mArrOrigin,mArrFromCopy,mArrFromMCopy,mArrOrigin,mArrFromCopy,mArrFromMCopy);

輸出:

值:
mArrOrigin :(
    value1,
    value2,
    value3
) mArrFromCopy:(
    value1,
    value2
) mArrFromMCopy(
    value1,
    value2
)
地址:
mArrOrigin :0x7fe102d0e380 
mArrFromCopy:0x7fe102d26070
mArrFromMCopy:0x7fe102d26090

現(xiàn)象:mArrFromCopy,mArrFromMCopy出來(lái)的容器本身是新的地址。(不可變?nèi)萜魍?br> 結(jié)論:copy和mutableCopy出來(lái)的是新的地址,原容器改變,新容器不改變。賦值結(jié)構(gòu)圖如下

容器賦值結(jié)構(gòu)示意圖2

容器本身不變,那么里面的元素呢?
我們修改原來(lái)容器中元素的值mstr1,輸出三個(gè)容器,觀察他們的值是否會(huì)改變,從而來(lái)判斷容器對(duì)象的copy和mutableCopy賦值是否元素也會(huì)深拷貝

[mstr1 appendString:@"-change2"];
NSLog(@"值:mArrOrigin :%@ mArrFromCopy:%@ mArrFromMCopy%@\n  地址:mArrOrigin :%p\n mArrFromCopy:%p\n mArrFromMCopy:%p\n",mArrOrigin,mArrFromCopy,mArrFromMCopy,mArrOrigin,mArrFromCopy,mArrFromMCopy);

輸出

值:
mArrOrigin :(
    "value1-change2",
    value2,
    value3
) mArrFromCopy:(
    "value1-change2",
    value2
) mArrFromMCopy(
    "value1-change2",
    value2
) 
地址:
mArrOrigin :0x7fe102d0e380
mArrFromCopy:0x7fe102d26070
mArrFromMCopy:0x7fe102d26090

現(xiàn)象:mArrFromCopy,mArrFromMCopy的元素隨之改變
結(jié)論:容器的copy和mutableCopy賦值中,容器本身是深拷貝,容器中的元素依舊是淺拷貝
結(jié)構(gòu)示意圖如下:


容器賦值結(jié)構(gòu)示意圖3

綜上所述:
1.copy和mutableCopy都是深拷貝
2.copy和mutableCopy生成的內(nèi)存地址上的數(shù)據(jù)是否可變跟原值類型和被賦值的指針類型無(wú)關(guān)。
如不可變數(shù)據(jù)copy出來(lái)的內(nèi)存,用可變指針指向,當(dāng)你嘗試修改的時(shí)候,仍然會(huì)發(fā)生崩潰。提示不可修改

3.容器對(duì)象本身遵循上面規(guī)則,容器中的元素依舊是淺拷貝(即多個(gè)指針指向一個(gè)數(shù)據(jù)地址)

項(xiàng)目地址https://github.com/ai966669/lbCopyAndMutableCopy

交流qq:578172874

錯(cuò)誤之處希望能幫忙提出來(lái),一起學(xué)習(xí),O(∩_∩)O謝謝了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 不敢說(shuō)覆蓋OC中所有copy的知識(shí)點(diǎn),但最起碼是目前最全的最新的一篇關(guān)于 copy的技術(shù)文檔了。后續(xù)發(fā)現(xiàn)有新...
    zyydeveloper閱讀 3,744評(píng)論 4 35
  • 為什么很多內(nèi)置類如UITableView的delegate屬性都是assign而不是retain? 所有的引用計(jì)數(shù)...
    煙雨平生花飛舞閱讀 1,282評(píng)論 0 3
  • 簡(jiǎn)述深淺拷貝 我們實(shí)例化的對(duì)象存儲(chǔ)在堆區(qū),而指向?qū)ο蟮闹羔樢话愦鎯?chǔ)在棧區(qū)。我們需要知道這個(gè)前提。??實(shí)際上拷貝分為...
    刀客傳奇閱讀 5,030評(píng)論 11 6
  • 本文為轉(zhuǎn)載: 作者:zyydeveloper 鏈接:http://m.itdecent.cn/p/5f776a...
    Buddha_like閱讀 1,030評(píng)論 0 2
  • 如果想到了不去做還不如不去想
    M_152閱讀 249評(píng)論 0 0

友情鏈接更多精彩內(nèi)容