美文网首页
KVO 和 KVC

KVO 和 KVC

作者: 风依旧_c080 | 来源:发表于2021-08-13 11:32 被阅读0次

    一、KVO

    KVO的是KeyValue Observe的缩写,中文是键值观察。这是一个典型的观察者模式,利用它可以很容易使用实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身,在Objc中实现KVO则必须实现NSKeyValueObServing协议,不过幸运的是NSObject已经实现了该协议,因此几乎所哟的NSObjectd对象都可以使用KVO。iOS中有个Notification的机制,也可以获得通知,但这个机制需要有个Center,相比之下KVO更加简洁而直接。

    KVO的使用也很简单,就是简单的3步。

          1.注册需要观察的对象的属性addObserver:forKeyPath:options:context:

          2.实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用

          3.取消注册观察removeObserver:forKeyPath:context:

    这里有两种方式,一种是匹配keyPath,另一种是使用context

    Demo:事列

    A.注册需要观察的对象

    - (void)viewDidLoad

    {

        [super viewDidLoad];

        // 注册监听

        [self.moveView addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

        self.p.name = @"小明";

        [self.p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:PersonAgeContext];

    }

    B.实现

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

    {

        // 方式1.匹配keypath

        if ([keyPath isEqualToString:@"frame"]) {

            NSLog(@"self.moveView.y = %f", self.moveView.y);

        }

        // 方式2.上下文

        if (context == PersonAgeContext) {

            NSLog(@"%@%d岁了", self.p.name, self.p.age);

        }

    }

    C.移除监听

    -(void)dealloc // ARC模式下

    {

        [self.moveView removeObserver:self forKeyPath:@"frame"];

        [self.p removeObserver:self forKeyPath:@"age" context:PersonAgeContext];

    }

    KVO的 优势 :

            1.能够提供一种简单的方法实现两个对象间的同步。例如:model和view之间同步;

            2.能够对非我们创建的对象,即内部对象的状态改变作出响应,而且不需要改变内部对象(SKD对象)的实现;

            3.能够提供观察的属性的最新值以及先前值;

            4.用key paths来观察属性,因此也可以观察嵌套对象;

            5.完成了对观察对象的抽象,因为不需要额外的代码来允许观察值能够被观察

          缺点 :

            1.我们观察的属性必须使用strings来定义。因此在编译器不会出现警告以及检查;

            2.对属性重构将导致我们的观察代码不再可用;

            3.复杂的“IF”语句要求对象正在观察多个值。这是因为所有的观察代码通过一个方法来指向;

            4.当释放观察者时不需要移除观察者。

    二、KVC

    KVC的常用方法:

    - (id)valueForKey:(NSString *)key; -(void)setValue:(id)value forKey:(NSString *)key;

    valueForKey的方法根据key的值读取对象的属性,setValue:forKey:是根据key的值来写对象的属性。

    注意:

    (1). key的值必须正确,如果拼写错误,会出现异常

    (2). 当key的值是没有定义的,valueForUndefinedKey:这个方法会被调用,如果你自己写了这个方法,key的值出错就会调用到这里来

    (3). 因为类key反复嵌套,所以有个keyPath的概念,keyPath就是用.号来把一个一个key链接起来,这样就可以根据这个路径访问下去

    (4). NSArray/NSSet等都支持KVC

    KVC过程讲解:

    以 [object setValue:@"134567" forKey:@"uid"];为例子,来探究KVC的实现过程

    第一步:搜索

    1、首先搜索setKey:方法.(key指成员变量名, 首字母大写)

    2、上面的setter方法没找到, 如果类方法accessInstanceVariablesDirectly返回YES. 那么按 _key, _isKey,key, iskey的顺序搜索成员名.(NSKeyValueCodingCatogery中实现的类方法, 默认实现为返回YES)

    3、如果没有找到成员变量, 调用setValue:forUnderfinedKey:

    第二步:编译器处理

    被编译器处理后:

    // 首先找到对应sel

    SEL sel = sel_get_uid("setValue:forKey:");

    // 根据object->isa找到sel对应的IMP实现指针

    IMP method = objc_msg_lookup (object->isa,sel);

    // 调用指针完成KVC赋值

    method(object, sel, @"134567", @"uid");

    解释:

    1.先根据方法名通过C函数sel_get_uid拿到选择子sel

    2.使用C函数objc_msg_lookup通过对象指针,选择子获取函数实现指针

    3. 调用C函数method(object, sel, @"134567", @"uid"),实现KVC赋值

    引申:setValue和setObject区别

    setObject:ForKey: 是NSMutableDictionary特有的;setValue:ForKey:是KVC的主要方法

    setobject中的key和value可以为除了nil外的任何对象

    setValue中的key只能为字符串 value可以为nil也可以为空对象[NSNull null]以及全部对象

    相关文章

      网友评论

          本文标题:KVO 和 KVC

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