原理
当你观察一个对象时,一个新的类会动态被创建。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。自然,重写的 setter 方法会负责在调用原 setter方法之前和之后,通过调willChangeValueForKey: 和 didChangevlueForKey:这两个方法来通知所有观察对象值的更改。最后把这个对象的 isa 指针 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。不仅如此,Apple 还重写了 -class 方法,企图欺骗我们这个类没有变,就是原本那个类。
1.使用姿势 http://zhangbuhuai.com/understanding-kvo/
- 监听的时候传入上下文来区分
- 移除的时候根据上下文来移除
- 为了避免取消订阅时造成的crash,可以把取消订阅代码放在@try-@catch语句中
static void * zwContentSize = &zwContentSize;
- (void)viewDidLoad {
[super viewDidLoad];
// 1. subscribe
[_tableView addObserver:self
forKeyPath:NSStringFromSelector(@selector(contentSize))
options:NSKeyValueObservingOptionNew
context:zwContentSize];
}
// 2. responding
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (context == zwContentSize) {
// configure view
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc {
@try {
// 3. unsubscribe
[_tableView removeObserver:self
forKeyPath:NSStringFromSelector(@selector(contentSize))
context:zwContentSize];
}
@catch (NSException *exception) {
}
}
2.如何自己实现KVO http://tech.glowing.com/cn/implement-kvo/
3.手动设定KVO https://yq.aliyun.com/articles/30483
如果将一个对象设定成属性,这个属性是自动支持KVO的,如果这个对象是一个实例变量,那么,这个KVO是需要我们自己来实现的
//
// Student.m
// SuperNotification
//
// Copyright (c) 2014年 Y.X. All rights reserved.
//
#import "Student.h"
@implementation Student
@synthesize name = _name;
- (void)setName:(NSString *)name
{
_name = name;
}
- (NSString *)name
{
return _name;
}
// 手动设定KVO
- (void)setAge:(NSString *)age
{
[self willChangeValueForKey:@"age"];
_age = age;
[self didChangeValueForKey:@"age"];
}
- (NSString *)age
{
return _age;
}
// 该方法来告诉系统是否监听某个key
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{
// 如果监测到键值为age,则指定为非自动监听对象
if ([key isEqualToString:@"age"])
{
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
@end