深入理解copy和mutablecopy必須要先理解堆(heap)和棧(stack)的區別,以下鏈結來自stack overflow的詳細解答。簡要的一句話就是:
物件儲存在堆中,該物件在堆中便有了乙個記憶體位址,該位址屬於棧中的乙個變數(指標)這個變數在棧中也占有一段記憶體。
對於不可變物件copy是淺拷貝的,mutablecopy是深拷貝
copy
nsstring
*test =
@"abc"
;nsstring
*copytest = [test
copy
];nslog
(@"test(stack) = %p, test(heap) = %p"
,&test, test);
nslog
(@"copytest(stack) = %p, copytest(heap) = %p", ©test, copytest);
列印結果:
test(stack) = 0x7fff5a69baf8, test(heap) = 0x105564068
copytest(stack) = 0x7fff5a69baf0, copytest(heap) = 0x105564068
從列印結果來看test和copytest任然指向堆的同一塊記憶體,只是在棧中拷貝了乙個指標變數。屬於淺拷貝。當test改變之後copytest就不再跟它指向同一塊堆記憶體了。
證明如下:
test =
@"cde"
;nslog
(@"test(stack) = %p, test(heap) = %p"
,&test, test);
nslog
(@"copytest(stack) = %p, copytest(heap) = %p", ©test, copytest);
列印結果:
test(stack) = 0x7fff53eb6af8, test(heap) = 0x10bd490c8
copytest(stack) = 0x7fff53eb6af0, copytest(heap) = 0x10bd49068
改變test的內容之後,copytest任然指向原來的堆疊位址,說明copy能夠開闢了新的記憶體。起到防止源物件改變之後,copy物件不會被改變。
mutablecopy
nsstring
*test =
@"abc"
;nsstring
*copytest = [test
mutablecopy
];nslog
(@"test(stack) = %p, test(heap) = %p"
,&test, test);
nslog
(@"copytest(stack) = %p, copytest(heap) = %p"
, ©test, copytest);
列印結果:
test(stack) = 0x7fff59318af8, test(heap) = 0x1068e7068
copytest(stack) = 0x7fff59318af0, copytest(heap) = 0x7fe83ae07cb0
mutablecopy之後兩個物件的棧位址和堆位址都不同,說明test和copytest是兩個完全不同的物件。
從這裡可以理解為什麼copy稱為淺拷貝,mutablecopy稱為深拷貝。
copy拷貝物件之後如果源物件和拷貝物件都不發生改變那麼它們都指向同乙個堆位址(淺拷貝)。給人一種他們就是兩個指標指向同乙個物件的趕腳(retain就是這樣)。其實不然,當有乙個變數改變時他們的堆位址就不同了。說明不是一直指向同乙個物件的。而mutablecopy為深拷貝,只要一被執行之後副本的位址就同原來的堆位址就是不一樣了稱為深拷貝。
copy
nsmutablestring
*test = [
nsmutablestring
stringwithformat
:@"abc"
];nsmutablestring
*copytest = [test
copy
];nslog
(@"test(stack) = %p, test(heap) = %p"
,&test, test);
nslog
(@"copytest(stack) = %p, copytest(heap) = %p", ©test, copytest);
列印結果:
test(stack) = 0x7fff53791af8, test(heap) = 0x7fc55b51ffc0
copytest(stack) = 0x7fff53791af0, copytest(heap) = 0x7fc55b5204d0
由列印結果看出可變物件copy之後的物件與源物件完全不同,因為nsstring是不可變物件,我們雖然可以改變它的內容,改變之後它的位址就會發生改變就不是原來的物件了(這裡可能有人會覺得很奇怪為什麼說不可變物件,可是我明明可以改變它的內容,別急後面會給出答案!),對不可變物件執行copy會指向同一堆位址就是因為物件的不可變性。那麼定義nsmutable物件就說明我們會去改變它,系統就自動的開闢乙個新的記憶體了,記憶體位址就與原物件不一樣。
請看改變可變物件:
nsmutablestring
*test = [
nsmutablestring
stringwithformat
:@"abc"
];nsmutablestring
*copytest = [test c
opy];nslog
(@"test(stack) = %p, test(heap) = %p test()= %@"
,&test, test, test);
nslog
(@"copytest(stack) = %p, copytest(heap) = %p,copytest() = %@"
, ©test, copytest, copytest);
copy對於可變物件時是深拷貝。
[test
:@"d"
];nslog
(@"test(stack) = %p, test(heap) = %p , test()=%@"
,&test, test, test);
nslog
(@"copytest(stack) = %p, copytest(heap) = %p, copytest()=%@"
, ©test, copytest, copytest);
列印結果:
test(stack) = 0x7fff5002daf8, test(heap) = 0x7fcd9af1ceb0, test()= abc
copytest(stack) = 0x7fff5002daf0, copytest(heap) = 0x7fcd9af1ab90,copytest() = abc
test(stack) = 0x7fff5002daf8, test(heap) = 0x7fcd9af1ceb0 , test()=abcd
copytest(stack) = 0x7fff5002daf0, copytest(heap) = 0x7fcd9af1ab90, copytest()=abc
我們改變了源物件test之後,它的堆記憶體位址竟然沒有改變(不是說是可變物件嗎,為什麼記憶體位址又不變了啊,我是不是被騙了-。-)。原來可變物件是站在記憶體的位址的角度來看的。。
不可變物件:可以為理解為如果物件的內容改變了(abc->abcd),你的堆記憶體位址就會改變(比如物件變成你朋友了那位址就是他家的位址了),堆位址改變了你也就不是原來的物件了(內容位址都變了),那我原來的物件去**了啊,我還要用它怎麼辦,不好意思找不到了!所以說這個物件是不能變啊,改變了你就再也找不到他了(指標本來指向你家的位址現在指向朋友家的位址了)。論拷貝的作用來了^_^。
總結:淺拷貝拷貝指標(stack),深拷貝拷貝物件(heap也改變)
不可變物件的copy是淺拷貝,mutable是深拷貝
可變物件的copy或mutblecopy位址都是深拷貝。
關於物件的copy方法
使用copy方法賦值,均為淺拷貝,不重新開闢記憶體位址,只是將物件指向同一記憶體位址 使用mutablecopy方法賦值,均為深拷貝,會從新開闢一塊記憶體位址 nsarray arr1 123213 nsarray arr2 arr1.copy nsarray arr3 arr1.mutableco...
Python深入類和物件
四,物件的自省機制 4.1 包含的函式有 dir type hasattr isinatance 得知物件的型別 判斷物件是否存在某個屬性 4.2 type 和isinstance 的區別 放在類中來考慮 isinstance 考慮到類中的繼承關係 type 不考慮類的繼承關係 例如 class a...
OC自定義物件的copy
一 概念 1 copy的目的在於修改源物件或者副本的時候互不影響 2 只有在不可變物件copy的時候才是淺拷貝,其餘都是深拷貝 二 自定義物件的copy 必須首先遵守nscopying協議 1 自定義物件copy的必要步驟 1 遵守nscopying協議 2 重寫 實現copywithzone 方法...