原文連接設計模式
Key-Value Observing 鍵值觀察 ,是一種設計模式觀察者模式的實現安全
官方定義編碼
鍵值觀察提供了一種機制,容許對象通知其餘對象的特定屬性的更改。它對應用程序中模型和控制器層之間的通訊特別有用。(在OS X中,控制器層綁定技術嚴重依賴於鍵值觀察。)控制器對象一般觀察模型對象的屬性,視圖對象經過控制器觀察模型對象的屬性。然而,另外,模型對象能夠觀察其餘模型對象(一般用於肯定從屬值什麼時候改變)或甚至自身(再次肯定從屬值什麼時候改變)。
先看下使用KVO的姿式atom
Xcode -> New -> MacOS -> CommandLine 新建工程,建立Person類設計
Person.hcode
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface Person : NSObject @property (nonatomic ,copy) NSString *name; @property (nonatomic ,assign) NSUInteger age; @property (nonatomic ,copy) NSArray<Person *> *friends; @end NS_ASSUME_NONNULL_END
Person.morm
#import "Person.h" @implementation Person - (instancetype)init { self = [super init]; if (self) { _name = @""; _age = 0; _friends = @[]; } return self; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { // 當收到通知的時候打印觀察的對象,舊值和新值 NSLog(@"\nReceving ObserveValueChanged \nObject: %@ OldValue: %@, NewValue: %@",object, change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]); } // 重寫以便打印對象的屬性 - (NSString *)description { return [NSString stringWithFormat:@"- name: %@, age: %ld, friends: %@",self.name, self.age, self.friends]; } @end
打開main.m,建立Alice和Bob,設置Bob觀察Alice的age屬性server
#import <Foundation/Foundation.h> #import "Person.h" static void *PersonChangeContext = &PersonChangeContext; int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... Person *Alice = Person.new; Alice.name = @"Alice"; Alice.age = 18; Person *Bob = Person.new; Bob.name = @"Bob"; Bob.age = 28; [Alice addObserver:Bob forKeyPath:@"age" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:PersonChangeContext]; Alice.age = 100; [Alice removeObserver:Bob forKeyPath:@"age"]; Alice.age = 200; } return 0; }
能夠看到控制檯輸出了一次Alice的age屬性的先後變化.對象
其中,NSKeyValueObservingOptions 有如下幾個選項,可使用 | 符號組合使用繼承
change字典的key值在這裏
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeKindKey; FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeNewKey; FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeOldKey; FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeIndexesKey; FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeNotificationIsPriorKey
KVO的使用場景有不少,好比Person擁有一個account屬性,person須要獲取account的變化該如何處理呢,輪訓或許是個辦法,可是無疑效率低下,並且很不安全,更合理的辦法就是使用KVO觀察account,在account發生變化時更新。
如今咱們已經知其然了,可是還不知其因此然。
先說結論
如何證實上述結論呢,上代碼!
#import <Foundation/Foundation.h> #import <objc/runtime.h> #import "Person.h" static void *PersonChangeContext = &PersonChangeContext; int main(int argc, const char * argv[]) { @autoreleasepool { Person *Alice = Person.new; Alice.name = @"Alice"; Alice.age = 18; Person *Bob = Person.new; Bob.name = @"Bob"; Bob.age = 28; Class cls0 = object_getClass(Alice); [Alice addObserver:Bob forKeyPath:@"age" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:PersonChangeContext]; Alice.age = 100; Class cls1 = object_getClass(Alice); NSLog(@"%@ %@",cls0,cls1); } return 0; }
Person NSKVONotifying_Person
能夠看到輸出確實如此
這就是KVO的核心思路了,關於KVC請看這裏.