前言
本文翻譯自蘋果文檔 Accessor Search Implementation Details 及方法的注釋。翻譯的不對的地方還請多多包涵指正,謝謝~
翻譯背景
在做熱修復的過程中,看到 JSPatch 的OC setter方法轉義成JavaScript代碼時,感到奇妙。代碼如下:
@interface WMPatchTest @property (nonatomic, strong) NSString *name; @end @implementation WMPatchTest - (void)setName:(NSString *)name { _name = name; } @end
defineClass('WMPatchTest', { setPayCompletion: function(name) { self.setValue_forKey(name, quot;_namequot;); }, });
代碼中在使用setKey:value:函數時,用的是 _name
,直接對protected屬性 _name
賦值。在用@property作屬性聲明,且getter和setter方法沒有都手動同時實現情況下,系統會自動創建一個protected屬性,屬性名是在property前面加上下劃線_ property。
Then,若想再深入具體了解KVC,請看下面翻譯的蘋果文檔~
KVC訪問器實現詳細
在KVC直接訪問實例變量前,會嘗試使用屬性的訪問方法。本篇文章講述了KVC是如何決定用哪種方法訪問屬性。
對于簡單屬性的 -setValue:forKey:
當 -setValue:forKey:
方法對一個屬性的默認實現調用后,判斷執行的順序如下:
-
首先搜索調用類的實例方法,實例方法的名字模式是
setlt;Keygt;
(即set字符串和key值的組合)。如果方法找到了,系統還會校驗方法參數。如果參數類型不是對象指針(id),但參數值為nil,則-setNilValueForKey:
被調用。-setNilValueForKey:
默認實現會拋出一個NSInvalidArgumentException
異常,但你可以重寫這個方法的實現。如果參數類型是對象指針,方法會簡單地校驗通過。若參數類型是其他類型(比如,int,CGPoint等),在方法-valueForKey:
調用前會自動把這些類型轉換成NSNumber或NSValue; -
如果方法沒找到,而且調用該方法的類方法
accessInstanceVariablesDirectly
返回的是YES,那么會查找該類實例的變量名字,依次匹配這些樣式:_lt;keygt;, _islt;Keygt;, lt;keygt;, islt;Keygt;
。如果找到匹配的變量,且變量是對象型,那么對象引用計數會增1且變量也會被賦值,之后原來變量指向的舊值引用計數會減1。若實例變量是其他類型(比如,int,CGPoint等),會想步驟1中一樣,先把NSNumber或NSValue轉成非對象類型再賦值; -
否則(方法和實例變量都沒找到),會調用
-setValue:forUndefinedKey:
方法。該方法默認實現會拋出一個NSUndefinedKeyException
異常,但你可以重寫它;
兼容性注意:
-
對于
-takeValue:forKey:
方法的向后二進制兼容,在步驟1中若方法名模式是-_setlt;Keygt;:
也會被識別。不過在Mac10.3系統后,KVC中以下劃線開頭的模式方法已廢棄; -
對于向后二進制兼容性,如果調用類參數不是對象型,則在步驟1中
-unableToSetNilForKey:
方法會代替-setNilValueForKey:
調用; -
步驟2中描述的行為與
-takeValue:forKey:
不同,后者在搜索類實例變量時只會去依次匹配lt;keygt;, _lt;keygt;
模式; -
步驟3中對于
-takeValue:forKey:
方法,如果調用類參數不是對象型,-handleTakeValue:forUnboundKey:
會代替-setValue:forUndefinedKey:
的調用;
栗子分析
再回頭看背景介紹的例子,name是WMPatchTest類屬性,編譯器會自動生成setter方法 -setName:
,getter方法 -name
,及私有變量 _name
。執行[WMPatchTest setValue:@quot;xxquot; forKey:@quot;_namequot;]時,首先進行步驟1,查找名字為 set_name
方法。發現沒有后,進行步驟2,檢查發現 accessInstanceVariablesDirectly
為YES后(默認是YES),依次讓類變量匹配這些樣式: _name, _isName, name, isName
, _name
被匹配并執行賦值操作;
后語
開發中,KVC的設置方法使用很頻繁,深入理解內部細節有助于我們開發提供更多思路,遇到異常情況時思路更清晰~
Tags: iOS開發
文章來源:http://www.jianshu.com/p/880957c3280f