KVO的原理, 底层实现

作者: chensifang | 来源:发表于2016-10-21 11:28 被阅读0次

    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: 0x11be08fc0>
    表面的类: ViewController
    真实类型: ViewController
    方法列表: dealloc , didReceiveMemoryWarning , viewDidLoad , c , setC: , a , b , setA: , setB:
    2016-10-21 11:10:40.971306 KVO[912:277637] 添加观察者之后:
    <ViewController: 0x11be08fc0>
    表面类型: 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的原理, 底层实现

        本文链接:https://www.haomeiwen.com/subject/txoquttx.html