在 Objective-C 中,KVO(Key-Value Observing)是通过运行时机制实现的。KVO 的底层主要依赖于 Objective-C 的消息机制和动态分发。下面将详细介绍 KVO 的底层实现原理,并提供简单的示例代码。
KVO 的实现原理
动态方法交换:当我们使用 KVO 时,系统会动态地为被观察的对象的属性生成一个子类 以NSKVONotifying_ + 类名,该子类重写了 getter 和 setter 方法。这个子类会在属性值被修改时发送通知。
通知机制:当属性值发生改变时,系统通过观察者模式通知所有注册的观察者。
消息转发:KVO 利用 Objective-C 的消息传递机制来实现对属性变化的监听和通知。
// 1. 定义被观察者
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end
@implementation Person @end
// 2. 观察者类
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[Person alloc] init];
self.person.name = @"Initial";
// 3. 注册观察者 (监听 name 属性变化)
[self.person addObserver:self
forKeyPath:@"name"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
}
// 4. 监听回调
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqualToString:@"name"]) {
NSLog(@"旧值: %@, 新值: %@", change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]);
}
}
// 5. 移除观察者 (非常重要!)
- (void)dealloc {
[self.person removeObserver:self forKeyPath:@"name"];
}
@end
手动关闭 KVO
重写这个方法
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
return NO;
}
如果关闭后还想要手动触发 KVO 需要手动调用在变量setter的前后 主动调用 willChangeValueForKey:和didChangeValueForKey:
[self.person willChangeValueForKey:@"name"];
self.person.name = @"Terry";
[self.person didChangeValueForKey:@"name"];