美文网首页
KVO&KVC分析

KVO&KVC分析

作者: woniu | 来源:发表于2018-04-03 16:12 被阅读11次

KVO和KVC应用还是比较广泛的。所以,今天我们就重新再学习下它们,以加深记忆。

一、KVO

1、KVO(key-value observing)定义

顾名思义“键值观察”,当观察对象发生改变的时候,对象会得到通知,然后做出相应的处理。观察者观察的是属性,只有遵循 KVO 变更属性值的方式才会执行 KVO 的回调方法,例如是否执行了 setter 方法、或者是否使用了 KVC 赋值。
如果赋值没有通过 setter 方法或者 KVC,而是直接修改属性对应的成员变量,例如:仅调用 _name = @"newName",这时是不会触发 KVO 机制,更加不会调用回调方法的。
所以使用 KVO 机制的前提是遵循 KVO 的属性设置方式来变更属性值。

2、KVO的基本原理
  • KVO是基于runtime机制实现的

  • 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制

  • 如果原类为Person,那么生成的派生类名为NSKVONotifying_Person

  • 每个类对象中都有一个isa指针指向当前类,当一个类对象第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法

  • 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。

3、使用流程

a、注册观察者,实施监听;
b、在回调方法中处理属性发生的变化;
c、移除观察者;

4、方法分析

a、注册观察者

//第一个参数 observer:观察者 (这里观察self.myKVO对象的属性变化)
//第二个参数 keyPath: 被观察的属性名称(这里观察 self.myKVO 中 num 属性值的改变)
//第三个参数 options: 观察属性的新值、旧值等的一些配置(枚举值,可以根据需要设置,例如这里可以使用两项)
//第四个参数 context: 上下文,可以为 KVO 的回调方法传值(例如设定为一个放置数据的字典)
[self.myKVO addObserver:self forKeyPath:@"num" options:
NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

b、属性变化收到的通知

//keyPath:属性名称
//object:被观察的对象
//change:变化前后的值都存储在 change 字典中
//context:注册观察者时,context 传过来的值
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
}

二、KVC

KVC(Key-value coding)顾名思义键值编码。简单来说,是可以通过对象属性名称(Key)直接给属性值(value)编码(coding),也可以说赋值。这样可以免去调用setter、getter方法,从而简化我们的代码。最最重要的是,它还可以用来修改系统控件内部的属性,我们在自定义控件属性的时候经常会用到(需要配合runtime)。

#import <Foundation/Foundation.h>
#import "KVO.h"
@interface KVC : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,retain) KVO *product;
@end
#import <Foundation/Foundation.h>

@interface KVO : NSObject
@property (nonatomic,assign) int num;
@property (nonatomic,copy) NSString *productName;
@end

使用场景:
 1、runtime中修改属性参数的地方,如导航栏透明、pageControl的背景图片。
 2、普通的对属性赋值。不过我们一般就直接访问属性了,这么做反而会麻烦些,且效率不高。

注意:KVC的性能并不能直接访问属性快,虽然这个性能消耗是微乎其微的。所以在使用KVC的时候,建议最好不要手动设置属性的setter、getter,这样会导致搜索步骤变长。
而且尽量不要用KVC进行集合操作,例如NSArray、NSSet之类的,集合操作的性能消耗更大,而且还会创建不必要的对象。

 
    KVC *model = [[KVC alloc]init];

    self.myKVO = [[KVO alloc]init];//大哥,别忘了初始化啊,这么低级的错误。
    /*
     1、未使用KVC的赋值
     myKVC.name = @"zhangsan";
     self.myKVO.productName = @"productName";
     myKVC.KVOModel = self.myKVO;
     self.myKVO.productName = @"productName";
     
     NSLog(@"---------------kvo:%@",self.myKVO.productName);
     */
    //2、使用KVC的赋值
    [model setValue:@"wangwu" forKey:@"name"];
 
    model.product = self.myKVO;
    NSLog(@"----------KVC:%@",[model valueForKeyPath:@"name"]);

    /*
     直接提取KVOModel中的属性值,用“.”分割
     因为类key反复嵌套,所以有个keyPath的概念,keyPath就是用.号来把一个一个key链接起来,这样就可以根据这个路径访问下去.
     */
    [model setValue:@"zhangsanfeng" forKeyPath:@"product.productName"];

    NSLog(@"----------kvc:%@",[model valueForKeyPath: @"product.productName"]);

runtime配合KVC修改属性

功能:修改UINavigationBar的左右两边的视图透明度。
注意:我们获取的_liftViews,_rightViews发现在iOS11里面不能用了,使用的话会崩溃。我们这里列出来它的调用方法作为示例分析。
[[self valueForKey:@"_liftViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
        view.alpha = alpha;
    }];

    [[self valueForKey:@"_rightViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
        view.alpha = alpha;
    }];

    UIView *titleView = [self valueForKey:@"_titleView"];
    titleView.alpha = alpha;

三、扩展

1、KVC与KVO的不同?

KVC(键值编码),即使用字符串访问一个实例变量的机制。而不是通过调用setter/getter等方法显式的存储方式访问。

2、notification比KVO有什么区别?

a、notification比KVO多了发送通知的一步,但是对象之间的直接交互,通知要明显的多,需要notificationCenter来做为中间交互。而KVO如我们介绍的,设置观察者->处理属性变化,至于中间通知这一环,是由系统处理的。
b、notification的优点时监听不局限于属性的变化,还可以对多种多样的变化进行监听,范围更广泛。(键盘、前后台等)

3、和delegate的不同?

相同点:
a、delegate,KVO和NSNotification的作用都是类与类之间的通信。
不同点:
a、KVO和NSNotification都是负责发送接收通知,剩下的事情交给系统处理,所以不用返回值,而delegate 则需要通信的对象通过变量(代理)联系
b、delegate是一对一,KVO和NSNotification这两个可以一对多。

Demo地址:https://github.com/caiqingchong/KVO-KVC.git
参考链接:
https://www.jianshu.com/p/e59bb8f59302
https://www.jianshu.com/p/7ba3d0eb4908

相关文章

  • KVO&KVC分析

    KVO和KVC应用还是比较广泛的。所以,今天我们就重新再学习下它们,以加深记忆。 一、KVO 1、KVO(key-...

  • KVO&KVC

    KVC KVC: key value coding 键值编码 通过KVC语法,可以修改对象中的属性。设置值时:例...

  • KVO&KVC

    一 KVO a) 介绍:Objective-C 中的键(key)-值(value)观察(KVO)来源...

  • iOS底层原理-KVO&KVC

    KVO&KVC KVO:键值监听,可以用于监听某个对象属性值的改变 以上是最简单的KVO的使用,通过打印perso...

  • KVC分析

    KVC是什么? kvc 是key value coding 的缩写,在ios中用于通过key,来获取value,即...

  • KVC分析

    KVO初探 根据官方文档我们来验证一下 set方法原文 1、两个方法要是同时存在会先找找setName方法,要是没...

  • KVC分析

    官方解释什么是KVC 翻译过来就是: 键值编码(Key-value coding)是由 NSKeyValueCod...

  • KVC分析

    methodswizzling面试题 method-swizzling的含义是方法交换,其主要作用是在运行时将一个...

  • iOS-KVC相关

    KVC相关 一、 iOS成员变量,实例变量,属性变量的区别 二、KVC取值、赋值原理 *学习方式:1、分析源码 -...

  • iOS基础全面分析之一(KVC全面分析)

    iOS基础全面分析之一(KVC全面分析)iOS基础全面分析之二(RunLoop全面分析)iOS基础全面分析之三(K...

网友评论

      本文标题:KVO&KVC分析

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