iOS偽拷貝, 淺拷貝, 深拷貝

2021-07-10 12:49:31 字數 4371 閱讀 1735

先來說說偽拷貝。

偽拷貝就是生成了乙個指標變數,指向了某乙個物件。

接下來我們來**下淺拷貝和深拷貝。

首先,從copy開始說,簡而言之,copy的目的就是生成乙個新的例項,然後把其成員都按原例項賦值。對於非指標型的成員,比如bool, int, float,這樣的賦值可以直接進行。但是對於指標型的資料,比如objc中用到的物件,就有deep copy和shallow copy的區別——這個和在c++中的基本上是一樣的:是生成新的成員物件,或是指向同一成員物件。

了解了這點以後,再看看copy在 objetive-c中的實現方式。如果要呼叫乙個物件的copy方法,這個物件必須遵循nscopying的協議。這個協議中規定了乙個方法:- (id)copywithzone: ( nszone * )zone;我們就是通過實現這個方法給物件提供拷貝的功能。對於很多現有類,如nsstring,nsdictionary,。。。這個方法已經實 現。假設我們現在自定義了乙個類,需要為這個類提供拷貝的功能,就需要自己來動手寫copywithzone的方法:示例如下:

這個是自定義的類:

@inte***ce

product : nsobject

@end

然後我們需要在product類中實現nscopying中的copywithzone方法:

- (id)copywithzone:(nszone *)zone

那麼這樣,如果我們有乙個product的例項, 假設為product1,然後呼叫product *product2 = [product1 copy];

就會使用我們上面寫的copywithzone的方法建立乙個product1的副本,然後賦值給product2。

這裡再以上面方法中的成員delegate為例,解釋一下deep copy和shallow copy:

在 copywithzone方法中,我們得到了乙個新的product例項,但是delegate是個物件,所以在副本中,我們可以選擇建立乙個新的 delegate物件(deep copy),或是指向同乙個delegate(shallow copy)。這個就取決於product類中的setdelegate:方法了。你可以選擇在setdelegate的時候,copy,也可以讓它們都指 向同乙個物件(但是需要retain,原因可以自己思考一下),當然,簡單assign在某種情況下也是可以的。

假設在product類中有setdelegate:方法,或是有delegate的property:

- (void)setdelegate: (id)adelegate

這 樣就是乙個深拷貝了,因為使用了delegate的copy方法得到了乙個delegate的副本。至於如何得到delegate的副本,就要看 delegate的copywithzone方法的實現了,不在這個層面的考慮中。也就是說,copy總是一中「遞迴」的形式,從上到下,我們可以一層一 層的考慮。

- (void)setdelegate: (id)adelegate

這樣操作後,delegate和adelegate為同一物件,但是為了記憶體管理方面的要求,我們呼叫了retain來將reference count加了一。當然,如果不需要了,還可以直接賦值(assign):

- (void)setdelegate: (id)adelegate
你可以把這個例子自己實現一下,然後用log打一打記憶體,這個結構就很明了了。

然後再說一下可變副本(mutable copy)和不可變副本(immutable copy):

一 般來說,如果我們的某個類需要區別對待這兩個功能——同時提供建立可變副本和不可變副本的話,一般在nscopying協議規定的方法 copywithzone中返回不可變副本;而在nsmutablecopying的mutablecopywithzone方法中返回可變副本。然後調 用物件的copy和mutablecopy方法來得到副本。

舉個例子:

nsdictionary類已經遵循了nscopying和nsmutablecopy的協議,也就是說我們可以呼叫它的copy和mutablecopy來得到不可變和可變的副本,程式如下:

nsdictionary *testdict = [[nsdictionary alloc]initwithobjectsandkeys:@」hello」, @」test」,nil];

nsdictionary *destdict = [testdict copy];

nslog(@」test dict:%p,retain count: %dndest dict:%p, retain count: %d」,testdict,[testdict retaincount],destdict,[destdict retaincount]);

這個在我機器上的執行結果為:

test dict:0x11f220, retain count: 2

dest dict:0x11f220,retain count: 2

看 起來,兩個dict指向了同一片記憶體區域,但是retaincount加了1。這點需要理解一下,因為我們使用nscopying方法要返回乙個不可變對 象。而且原來的testdict也是不可變的,那麼這裡的「副本」也就沒多大意義了(這就如同使用字串常量時,系統會為我們優化,宣告了多個字串,但 是都是常量,且內容相等,那麼系統就只為我們申請一塊空間,這個道理是一樣的)。既然都不可變,那麼指向同乙個空間就可以了。這裡的copy和 retain沒什麼區別。

我們使用copywithzone的方法返回immutable的物件,而不管原來的是可變的或是不可變的。我們再看一下如下**:

nsmutabledictionary *testdict = [[nsmutabledictionary alloc]initwithobjectsandkeys:@」hello」, @」test」,nil];

nsmutabledictionary *destdict = [testdict copy];

nslog(@」test dict:%p,retain count:%dndest dict:%p,retain count:%d」,testdict,[testdict retaincount],destdict,[destdict retaincount]);

[destdict setobject:@"what" forkey:@"test2"];

nsmutabledictionary是可變的,該**在我機器上執行的結果為:

test dict:0x20dcc0,retain count:1

dest dict:0×209120,retain count:1

* -[nscfdictionary setobject:forkey:]: mutating method sent to immutable object

可 以看到因為我們呼叫了可變物件的copy方法,這個不像之前的例子中一樣,只是retain了一下。這裡的test dict和dest dict已經是兩個物件了,但是,copywithzone的方法返回的是不可變的物件,因此之後的setobject: forkey:方法會出現錯誤。

下面這樣改一下就ok了。

nsmutabledictionary *testdict = [[nsmutabledictionary alloc]initwithobjectsandkeys:@」hello」, @」test」,nil];

nsmutabledictionary *destdict = [testdict mutablecopy];

nslog(@」test dict:%p,retain count:%dndest dict:%p,retain count:%d」,testdict,[testdict retaincount],destdict,[destdict retaincount]);

[destdict setobject:@"what" forkey:@"test2"];

nslog(@」destdict:%@」,destdict);

執行結果為:

test dict:0×123550,retain count:1

dest dict:0x10a460,retain count:1

因為我們使用了mutablecopy來得到了乙個可變副本。

note:對於系統提供的所有既支援nscopying,又支援nsmutablecopying的類。

copy方法,得到的是不可變物件,不管以前的是可變還是不可變。

mutablecopy方法,得到的是可變物件,不管以前的是可變還是不可變。

偽拷貝是指標變數直接指向物件空間;淺拷貝是指標變數指向了物件所處的空間,同時引起引用計數的變化(增加);深拷貝是指標變數指向了一塊複製出來的與原物件中內容一模一樣的新的空間。

淺拷貝 偽拷貝 深拷貝

偽拷貝 就是假拷貝 並沒有真正的拷貝 位址和 person01 位址一樣 兩個指向乙個位址 id copywithzone nszone zone 淺拷貝 物件是2個 但是內容是同乙個 人是兩份 拷貝的姓名是個指標 這種拷貝是把 name 的首位址給傳進來了 年齡拷貝進來了 但真的年齡還是乙份 id...

iOS 深拷貝淺拷貝例項

nsstring string 漢斯哈哈哈 沒有產生新物件 nsstring copystring string copy 產生新物件 nsmutablestring mutablecopystring string mutablecopy nslog string p copystring p m...

iOS深拷貝與淺拷貝

在大部分的程式語言中,都有深拷貝與淺拷貝的概念,如果使用深淺拷貝有誤,可能會造成資料安全性的問題,那麼本節針對oc中的深淺拷貝展開討論 深拷貝與淺拷貝的概念 我們在進行例項物件操作時,無非是兩種例項方式 建立新物件後將原物件的內容拷貝乙份,而後返回該物件引用 深淺拷貝的區別由此產生 以下是b物件拷貝...