Day28
1.KVO實現原理:
.當某個類的對象第一次被觀察時,系統就會在運行期動態地創建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的setter方法。
.派生類在被重寫的setter方法中實現真正的通知機制,就如前面手動實現鍵值觀察那樣。這麼做是基於設置屬性會調用 setter方法,而通過重寫就獲得KVO需要的通知機制。當然前提是要通過遵循KVO的屬性設置方式來變更屬性值,如果僅是直接修改屬性對應的成員變量,是無法實現KVO的。
.同時派生類還重寫了class方法以“欺騙”外部調用者它就是起初的那個類。然後系統將這個對象的isa 指針指向這個新誕生的派生類,因此這個對象就成為該派生類的對象了,因而在該對像上對setter的調用就會調用重寫的setter,從而激活鍵值通知機制。此外,派生類還重寫了dealloc方法來釋放資源。
2.change參數
默認change參數會包含一個NSKeyValueChangeKindKey鍵值對,傳遞被監聽屬性的變化類型:
typedef NS_ENUM(NSUInteger, NSKeyValueChange) {
NSKeyValueChangeSetting = 1,
NSKeyValueChangeInsertion = 2,
NSKeyValueChangeRemoval = 3,
NSKeyValueChangeReplacement = 4,
};
NSKeyValueChangeSetting =屬性的值被重新設置;
NSKeyValueChangeInsertion、NSKeyValueChangeRemoval、NSKeyValueChangeReplacement =表示更改的是集合屬性,分別代表插入、刪除、替換操作。
如果NSKeyValueChangeKindKey參數是針對集合屬性的三個之一,change參數還會包含一個NSKeyValueChangeIndexesKey鍵值對,表示變化的index。
(chang字典裡,新值的key為“new”,舊值的key為“old”,變化類型的key為“kind”。)
3、自動通知和手動通知
由於KVO會自動通知觀察者(默認)。固取消自動通知的方法是實現下面的類方法,透過返回NO來取消自動通知。
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key
系統也會單獨針對這個屬性自動生成相關的類方法,是否自動通知這個屬性被改變,也可以單獨重寫這個類方法:
//假如有一個屬性 @property (copy, nonatomic) NSString *str; //則系統會自動生成關於這個屬性的類方法,是否自動通知 + (BOOL)automaticallyNotifiesObserversOfTest;
針對非自動通知的屬性,可以分別在變化之前和之後手動調用如下方法(will在前,did在後)來手動通知觀察者:
- (will/did)ChangeValueForKey: - (will/did)ChangeValueForKey:withSetMutation:usingObjects: - (will/did)Change:valuesAtIndexes:forKey:
好處:可以靈活加上自己想要的判斷條件,事實上自動通知也是框架通過調用這些方法實現的。
4.觸發KVO的三種方式:
有訪問器方法,則運行時會在訪問器方法中調用will/didChangeValueForKey:方法;沒有訪問器方法,運行時 會在 setValue:forKey:方法中調用will/didChangeValueForKey:方法。
直接使用了訪問器方法(點語法),會在運行時重寫setter方法,調用will/didChangeValueForKey:方法;
顯示調用will/didChangeValueForKey:方法。