KVO的原理, 底层实现

1. 概念

KVO,即:Key-Value Observing,键值观察,它提供一种监听属性变化的机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会带上修改前后的值自动通知相应的观察者了。

2. 方法

  1. 注册观察者
    addObserver:forKeyPath:options:context:

  2. 观察者实现
    observeValueForKeyPath:ofObject:change:context:

  3. 移除观察者
    removeObserver:forKeyPath:

3. 验证底层实现

给ViewController类添加3个属性(用于观察)

@interface ViewController : UIViewController
@property (nonatomic, assign) int a;
@property (nonatomic, assign) int b;
@property (nonatomic, assign) int c;
@end

Appdelegate中验证

@implementation AppDelegate

// 获取类的方法列表
+ (NSArray*)classMethodList:(Class)class {
    NSMutableArray* array = [NSMutableArray array];
    unsigned int count = 0;
    Method* methodList = class_copyMethodList(class, &count);
    for(int i = 0; i < count; ++i) {
        SEL sel = method_getName(*(methodList+i));
        [array addObject:NSStringFromSelector(sel)];
    }
    free(methodList);
    return array;
}

// 打印对象的信息
+ (NSString *)logInfo:(id)obj {
    NSString* string = [NSString stringWithFormat:@"\t%@\n\t表面的类: %@\n\t真实类型: %@\n\t方法列表: %@\n",
                        obj,
                        [obj class],
                        object_getClass(obj),
                        [[self classMethodList:object_getClass(obj)] componentsJoinedByString:@" , "]];
    return string;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ViewController *vc = [[ViewController alloc] init];
    NSLog(@"添加观察者之前:\n%@", [AppDelegate logInfo:vc]);
    
    [vc addObserver:vc forKeyPath:@"a" options:NSKeyValueObservingOptionNew context:nil];
    NSLog(@"添加观察者之后:\n%@", [AppDelegate logInfo:vc]);
    return YES;
}
@end


打印结果:

2016-10-21 11:10:40.970662 KVO[912:277637] 添加观察者之前:

表面的类: ViewController
真实类型: ViewController
方法列表: dealloc , didReceiveMemoryWarning , viewDidLoad , c , setC: , a , b , setA: , setB:
2016-10-21 11:10:40.971306 KVO[912:277637] 添加观察者之后:

表面类型: ViewController
真实类型: NSKVONotifying_ViewController
方法列表: setA: , class , dealloc , _isKVOA


Log分析:

  1. 注册KVO之后, a的表面类型仍然是ViewController, 但是运行时的类型是NSKVONotifying_ViewController, 可见系统在运行时创建了一个ViewController的子类(别问我为什么是子类)NSKVONotifying_ViewController, 将a对象的isa指针指向NSKVONotifying_ViewController.
  1. 注册KVO后重写了setA:方法, 系统便是在这个方法中带上属性改变前后的值通知观察者.
  2. 注册KVO后setB:, setC:方法不用重写, 因为并未被观察.
  3. 注册KVO后重写了class方法, 使他仍然返回ViewController类型, 让改变a对象真实类型显得更加隐蔽.
  4. 注册KVO后出现 _isKVOA, 猜测这个方法用来标识这是否是一个注册KVO后生成的类.

喜欢的猿友们点个赞哈!!!

你可能感兴趣的:(KVO的原理, 底层实现)