KVO&KVC分析

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 *)change context:(void *)context
{
}

二、KVC

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

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

@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分析)