本文邏輯圖

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)圖如下:

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)圖如下

容器本身不變,那么里面的元素呢?
我們修改原來(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)示意圖如下:

綜上所述:
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謝謝了