原文连接设计模式
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请看这里.