KVO的底层工作原理:
1.准备一个Person对象,作为被监听对象
2.准备一个Observer_Person,作为监听者
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@property (nonatomic, strong) Observer_Person*observer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do anyadditional setup after loading the view, typically from a nib.
self.person = [Person new]; //被监听对象
self.observer = [Observer_Person new]; //监听者
[self.person addObserver:self.observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {
self.person.age= 10; //在此处打断点,方便查看Person对象的内部结构
}
当程序运行起来时,点击屏幕,会在断点处停下,打开Xcode输出辅助试图,可以看到person对象内部的isa指针指向的是一个NSKVONotifying_Person对象,这个对象是runtime运行时动态生成一个Person的子类,
在这个子类中,runtime会动态的添加(重写父类set方法)被修改属性的set方法(即setAge:),然后在set方法中,调用willChangeValueForKey/didChangeValueForKey,向系统发出NSKeyValueChangeSetting的通知,然后系统的通知中心,就会通知监听者,调用-observeValueForKeyPath:ofObject:change:context:方法来实现监听被监听者的值改变
模拟runtime的动态给被修改属性生成set方法的实现。
- (void)setAge:(int)age{
[super setAge:age];
[self willChangeValueForKey:@"age"];
[self didChangeValueForKey:@"age"];
}
下面代码摘自苹果官方API头文件
@interfaceNSObject(NSKeyValueObserverNotification)
/* Given a key that identifies a property (attribute,to-one relationship, or ordered or unordered to-many relationship), send-observeValueForKeyPath:ofObject:change:context: notification messages of kind NSKeyValueChangeSetting to each observerregistered for the key, including those thatare registered with other objects using key paths that locate the keyed valuein this object. Invocations of these methods must always be paired.
Thechange dictionaries in notifications resulting from use of these methodscontain optional entries if requested at observer registration time:
- The NSKeyValueChangeOldKey entry, if present, contains the valuereturned by -valueForKey: at the instant that -willChangeValueForKey: isinvoked (or an NSNull if -valueForKey: returns nil).
- The NSKeyValueChangeNewKey entry, if present, contains the valuereturned by -valueForKey: at the instant that -didChangeValueForKey: is invoked(or an NSNull if -valueForKey: returns nil).
*/
- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;
@end