本篇主要是介紹KVC和KVO的使用方法和實(shí)現(xiàn)原理
基本概念:
1-1. KVC基本概念:
KVC 即 Key-Value Coding,翻譯成鍵值編碼。它是一種不通過存取方法,而通過屬性名稱字符串間接訪問屬性的機(jī)制。
? 1-2. KVC的基本用法:
? KVC 常用到的方法有下面幾個:
? - (id)valueForKey:(NSString *)key;
? - (void)setValue:(nullable id)value forKey:(NSString *)key;
?- (nullable id)valueForKeyPath:(NSString *)keyPath;
? - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
1-3. KVC的基本原理
KVC的原理 為了設(shè)置或者獲取對象屬性,KVC按順序使用如下技術(shù): 獲取對象屬性時(shí),檢查是否存在 -?<key>, ?-is<key>(只針對布爾值有效)或者 -ge<key>t的訪問器方法,如果找到,就用這些方法來返回屬性值;設(shè)置對象屬性時(shí),檢查是否存在名為 -set<key>: 的方法,并使用它來設(shè)置屬性值。對于 -get<key>和 -set<key>: 方法,將大寫Key字符串的第一個字母,并與Cocoa的方法命名保持一致。 如果上述方法找不到,則檢查名為 -_<key>、 -_is<key>(只針對布爾值有效)、 -_get<key>和 -_set<key>: 方法。 如果沒有找到訪問器方法,則嘗試直接訪問實(shí)例變量。實(shí)例變量可以是名為:<key>或 _<key> 。
? ? 如果仍未找到,則調(diào)用 valueForUndefinedKey: 和 setValue:forUndefinedKey: 方法。這些方法的默認(rèn)實(shí)現(xiàn)都是拋出異常,可以根據(jù)需要重寫它們。
? ? 可以看到,KVC會優(yōu)先使用訪問器方法來訪問對象屬性。
2-1. KVO的基本概念:
?KVO 即 Key-Value Observing,翻譯成鍵值觀察。它是一種觀察者模式的衍生。其基本思想是,對目標(biāo)對象的某屬性添加觀察,當(dāng)該屬性發(fā)生變化時(shí),通過觸發(fā)觀察者對象實(shí)現(xiàn)的KVO接口方法,來自動的通知觀察者。
? ?KVO可以在MVC模式中得到很好的應(yīng)用。因?yàn)楫?dāng)Model發(fā)生變化時(shí),通過KVO可以很方便地通知到Controller,從而通過Controller來改變View的展示。所以說KVO是解決Model和View同步的好辦法。
2-2. KVO的基本用法 ?(最好配合單例使用) :
?KVO的使用主要分為三步:
?第一步,將目標(biāo)對象添加為觀察者。(注意這里用到了KVC,即通過字符串的方式去訪問屬性值。但是,也可以不用,直接更改其屬性)?
?- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;?
?第二步,實(shí)現(xiàn)接收通知的接口方法。
?- (void)observeValueForKeyPath:(nullable NSString *)keyPath ?ofObject:(nullable id)object ? ? ?change:(nullable NSDictionary *)change ? ? ?context:(nullable void *)context;
? ? 第三步,移除觀察者。
? ? - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
2-3. KVO的原理
KVO的實(shí)現(xiàn)依賴于Runtime的強(qiáng)大動態(tài)能力。
當(dāng)某個類的對象第一次被觀察時(shí),系統(tǒng)就會在運(yùn)行期動態(tài)地創(chuàng)建該類的一個派生類,在這個派生類中重寫這個類中任何被觀察屬性的 setter 方法。
即當(dāng)一個類型為 ObjectA 的對象,被添加了觀察后,系統(tǒng)會生成一個 NSKVONotifying_ObjectA 類,并將對象的isa指針指向新的類,也就是說這個對象的類型發(fā)生了變化。這個類相比較于ObjectA,會重寫以下幾個方法。
1. 重寫setter
在 setter 中,會添加以下兩個方法的調(diào)用。
- (void)willChangeValueForKey:(NSString*)key;
- (void)didChangeValueForKey:(NSString*)key;
然后在?didChangeValueForKey:?中,去調(diào)用:
- (void)observeValueForKeyPath:(nullableNSString*)keyPath ofObject:(nullableid)object change:(nullableNSDictionary *)change context:(nullablevoid*)context;
于是實(shí)現(xiàn)了屬性值修改的通知。因?yàn)?KVO 的原理是修改 setter 方法,因此使用 KVO 必須調(diào)用 setter 。若直接訪問屬性對象則沒有效果。
具體demo:KVC-KVO-Demo