首先,從copy開始說,簡而言之,copy的目的就是生成一個新的實例,然後把其成員都按原實例賦值。對於非指針型的成員,比如BOOL,
int, float,這樣的賦值可以直接進行。但是對於指針型的數據,比如Objc中用到的對象,就有Deep Copy和Shallow Copy的區別——這個和在C++中的基本上是一樣的:是生成新的成員對象,或是指向同一成員對象。
瞭解了這點以後,再看看Copy在 Objetive-C中的實現方式。如果要調用一個對象的copy方法,這個對象必須遵循NSCopying的協議。這個協議中規定了一個方法:-
(id)copyWithZone: ( NSZone * )zone;我們就是通過實現這個方法給對象提供拷貝的功能。對於很多現有類,如NSString,NSDictionary,。。。這個方法已經實 現。假設我們現在自定義了一個類,需要爲這個類提供拷貝的功能,就需要自己來動手寫CopyWithZone的方法:示例如下:
這個是自定義的類:
然後我們需要在Product類中實現NSCopying中的copyWithZone方法:
那麼這樣,如果我們有一個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:
這 樣就是一個深拷貝了,因爲使用了delegate的copy方法得到了一個delegate的副本。至於如何得到delegate的副本,就要看
delegate的copyWithZone方法的實現了,不在這個層面的考慮中。也就是說,copy總是一中“遞歸”的形式,從上到下,我們可以一層一 層的考慮。
這樣操作後,delegate和aDelegate爲同一對象,但是爲了內存管理方面的要求,我們調用了retain來將reference
count加了一。當然,如果不需要了,還可以直接賦值(assign):
你可以把這個例子自己實現一下,然後用log打一打內存,這個結構就很明瞭了。
然後再說一下可變副本(mutable copy)和不可變副本(immutable copy):
可變和不可變的概念,我們之前通過NSDictionary和NSMutableDictionary的區別瞭解過。
一 般來說,如果我們的某個類需要區別對待這兩個功能——同時提供創建可變副本和不可變副本的話,一般在NSCopying協議規定的方法 copyWithZone中返回不可變副本;而在NSMutableCopying的mutableCopyWithZone方法中返回可變副本。然後調 用對象的copy和mutableCopy方法來得到副本。
舉個例子:
NSDictionary類已經遵循了NSCopying和NSMutableCopy的協議,也就是說我們可以調用它的copy和mutableCopy來得到不可變和可變的副本,程序如下:
這個在我機器上的運行結果爲:
test Dict:0x11f220, retain Count: 2
dest Dict:0x11f220,retain Count: 2
看 起來,兩個dict指向了同一片內存區域,但是retainCount加了1。這點需要理解一下,因爲我們使用NSCopying方法要返回一個不可變對 象。而且原來的testDict也是不可變的,那麼這裏的“副本”也就沒多大意義了(這就如同使用字符串常量時,系統會爲我們優化,聲明瞭多個字符串,但 是都是常量,且內容相等,那麼系統就只爲我們申請一塊空間,這個道理是一樣的)。既然都不可變,那麼指向同一個空間就可以了。這裏的copy和 retain沒什麼區別。
我們使用copyWithZone的方法返回immutable的對象,而不管原來的是可變的或是不可變的。我們再看一下如下代碼:
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了。
運行結果爲:
test Dict:0×123550,retain count:1
dest Dict:0x10a460,retain count:1
因爲我們使用了mutableCopy來得到了一個可變副本。
Note:對於系統提供的所有既支持NSCopying,又支持NSMutableCopying的類。
copy方法,得到的是不可變對象,不管以前的是可變還是不可變。
mutableCopy方法,得到的是可變對象,不管以前的是可變還是不可變。
copy 的實現原理與深淺拷貝
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
遇到libc++abi.dylib handler threw exception這樣的異常,查找異常原因
@try{ } @catch(NSException *exception) { NSLog(@"exception:%@", exception); }
chun799
2020-06-27 21:10:40
應用內跳轉到設置相關頁面
chun799
2020-06-27 21:10:40
ios8 強制旋轉問題 (xcode6)
http://www.devdiv.com/iOS_iPhone-ios_xcode_-thread-211995-1-1.html
chun799
2020-06-27 21:10:40
設置全局導航,button,UITextField樣式
chun799
2020-02-24 16:53:28
蘋果公司聯繫郵箱大全
chun799
2020-02-24 16:53:28
iOS7之NSURLSession
chun799
2020-02-24 16:53:28
Exif的Orientation
chun799
2020-02-24 16:53:28
App適配iPhone 6/ Plus和iOS 8
chun799
2020-02-24 16:53:28
採用現代Objective-C
chun799
2020-02-24 16:53:28
iOS 用其它應用打開文件
chun799
2020-02-24 16:53:28
iOS7 新後臺及下載SDK介紹
chun799
2020-02-24 16:53:28
copy和mutableCopy
chun799
2018-09-04 03:39:14