首先,從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):
可變和不可變的概念,我們之前通過nsdictionary和nsmutabledictionary的區別了解過。
一 般來說,如果我們的某個類需要區別對待這兩個功能——同時提供建立可變副本和不可變副本的話,一般在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: %d\ndest 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:%d\ndest 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:0x209120,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:%d\ndest dict:%p,retain count:%d",testdict,[testdict retaincount],destdict,[destdict retaincount]);
[destdict setobject:@"what" forkey:@"test2"];
nslog(@"destdict:%@",destdict);
執行結果為:
test dict:0x123550,retain count:1
dest dict:0x10a460,retain count:1
destdict:{
test = hello;
test2 = what;
因為我們使用了mutablecopy來得到了乙個可變副本。
note:對於系統提供的所有既支援nscopying,又支援nsmutablecopying的類。
copy方法,得到的是不可變物件,不管以前的是可變還是不可變。
mutablecopy方法,得到的是可變物件,不管以前的是可變還是不可變。
關於python深copy與淺copy的一點理解
一直對python深copy和淺copy似懂非懂的狀態,看了這篇文章,覺得自己懂了很多,給各位參考!出處 import copy a 1 不可變資料型別 copy a copy.copy a print id a id copy a 記憶體位址相同 a 1,2 可變資料型別 copy a copy....
copy 的實現原理與深淺拷貝
首先,從copy開始說,簡而言之,copy的目的就是生成乙個新的例項,然後把其成員都按原例項賦值。對於非指標型的成員,比如bool,int,float,這樣的賦值可以直接進行。但是對於指標型的資料,比如objc中用到的物件,就有deep copy和shallow copy的區別 這個和在c 中的基本...
copy 的實現原理與深淺拷貝
首先,從copy開始說,簡而言之,copy的目的就是生成乙個新的例項,然後把其成員都按原例項賦值。對於非指標型的成員,比如bool,int,float,這樣的賦值可以直接進行。但是對於指標型的資料,比如objc中用到的物件,就有deep copy和shallow copy的區別 這個和在c 中的基本...