KVO的基本实现原理

KVO的实现是基于Runtime机制的,主要通过动态创建子类并重写setter方法来实现。具体步骤如下:

  1. 动态创建子类
  • 当你对一个对象第一次调用addObserver:forKeyPath:options:context:方法时
  • 系统会动态创建一个新的类,类名通常为NSKVONotifying_原类名
  • 这个新类继承自原类
  1. 重写setter方法
    新创建的子类中重写了被观察属性的setter方法,大致实现如下:
- (void)setSomeProperty:(id)newValue {
    [self willChangeValueForKey:@"someProperty"];
    
    // 调用父类的setter方法
    [super setSomeProperty:newValue];
    
    [self didChangeValueForKey:@"someProperty"];
}
  1. 修改isa指针
  • 系统将对象的isa指针指向新创建的子类
  • 这样当属性发生改变时,就会调用子类重写的setter方法

具体实现示例

// 原始类
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end

// 使用KVO
Person *person = [[Person alloc] init];
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

当添加观察者后,Runtime会创建一个新的类:

// KVO动态创建的子类(简化版)
@interface NSKVONotifying_Person : Person
@end

@implementation NSKVONotifying_Person

- (void)setName:(NSString *)name {
    [self willChangeValueForKey:@"name"];
    [super setName:name];
    [self didChangeValueForKey:@"name"];
}

// 重写class方法,隐藏KVO的实现细节
- (Class)class {
    return [Person class];
}

@end

验证KVO的实现

你可以通过以下代码验证KVO的实现原理:

Person *person = [[Person alloc] init];
NSLog(@"Before KVO: %@", object_getClass(person));
    
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"After KVO: %@", object_getClass(person));

输出结果会类似:

Before KVO: Person
After KVO: NSKVONotifying_Person

注意事项

  1. KVO是自动触发的,但必须通过setter方法修改属性才能触发
  2. 直接修改实例变量不会触发KVO
  3. 必须在不再需要观察时移除观察者,否则可能导致崩溃
  4. iOS 12之后,苹果引入了新的KVO API,使用block的方式更加安全和便捷
// 新的KVO API
person.observe(\.name, options: [.new]) { object, change in
    print("name changed to: \(change.newValue)")
}

这就是KVO的基本实现原理,它是iOS中一个非常重要的观察者模式的实现。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容