美文网首页
iOS - 《KVC与KVO》

iOS - 《KVC与KVO》

作者: baiwulong | 来源:发表于2017-12-25 12:20 被阅读21次

KVC(Key-value coding)键值编码,指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。
KVC可以不通过getter/setter方法来访问对象的属性。
因为一个类的成员变量如果没有提供getter/setter的话,外界就失去了对这个变量的访问渠道。而KVC则提供了一种访问的方法,这个在某些场合会很有威力。例如,直接修改系统控件的内部属性

KVO 是 Objective-C 对观察者设计模式的一种实现。【另外一种是:通知机制(notification)】;
KVO提供一种机制,指定一个被观察对象(例如A类),当对象某个属性(例如A中的字符串name)发生更改时,监听对象会获得通知,并作出相应处理;【且不需要给被观察的对象添加任何额外代码,就能使用KVO机制】
在MVC设计架构下的项目,KVO机制很适合实现mode模型和view视图之间的通讯。

KVC(Key-value coding)

下面是KVC最为重要的四个方法

- (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值
+ (BOOL)accessInstanceVariablesDirectly;
//默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索

- (nullable id)valueForUndefinedKey:(NSString *)key;
//如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。

- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//和上一个方法一样,但这个方法是设值。

- (void)setNilValueForKey:(NSString *)key;
//如果你在SetValue方法时面给Value传nil,则会调用这个方法

修改系统控件的内部属性(Runtime+KVC)

比如修改tabbar底部控制栏的tabbar为自定义tabbar类型,就可以通过kvc来实现。
有时候一些属性是私有变量,可以通过runtime来查找属性值

/**
 *  运行时(runtime),获取所有成员变量
 */
- (void)getMemberVariables
{
    unsigned ivarCount;
    Ivar *ivars = class_copyIvarList([UIPageControl class], &ivarCount);
    
    for (int i = 0; i < ivarCount; i ++) {
        
        NSString *varibale = [NSString stringWithUTF8String:ivar_getName(ivars[i])];
        
        NSLog(@"%@",varibale);
    }
}


通过KVC来修改
UIPageControl *pageControl = [[UIPageControl alloc ] init];
[pageControl setValue:[UIImage imageNamed:%@"nomal.png"] forKey:@"_pageImage"];
[pageControl setValue:[UIImage imageNamed:%@"selected.png"] forKey:@"_currentPageImage"]

KVC底层原理分析

setValue:forKey:赋值原理如下

  • 去模型中查找有没有对应的setter方法:例如:setIcon方法,有就直接调用这个setter方法给模型这个属性赋值[self setIcon:dic[@"icon"]];
  • 如果找不到setter方法,接着就会去寻找有没有icon属性,如果有,就直接访问模型中的icon属性,进行赋值,icon=dict[@"icon"];
  • 如果找不到icon属性,接着又会去寻找_icon属性,如果有,直接进行赋值_icon=dict[@"icon"];
  • 如果都找不到就会报错:[<Flag 0X7fb74bc7a2c0> setValue:forUndefinedKey:]
  • 如果对某个类,不允许使用KVC,可以通过设置 accessInstanceVariablesDirectly 控制。
    KVC内部的实现

比如说如下的一行KVC的代码:

[site setValue:@"sitename" forKey:@"name"];
就会被编译器处理成:

SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (site->isa,sel);
method(site, sel, @"sitename", @"name");

这下KVC内部的实现就很清楚的清楚了:一个对象在调用setValue的时候,

  • (1)首先根据方法名找到运行方法的时候所需要的环境参数。
  • (2)他会从自己isa指针结合环境参数,找到具体的方法实现的接口。
  • (3)再直接查找得来的具体的方法实现。

/
/
/
/
/

KVO

KVO 是 Objective-C 对观察者设计模式的一种实现。【另外一种是:通知机制(notification)】;

KVO提供一种机制,指定一个被观察对象(例如A类),当对象某个属性(例如A中的字符串name)发生更改时,监听对象会获得通知,并作出相应处理;【且不需要给被观察的对象添加任何额外代码,就能使用KVO机制】
在MVC设计架构下的项目,KVO机制很适合实现mode模型和view视图之间的通讯。

notification比KVO多了发送通知的一步。

两者都是一对多,但是对象之间直接的交互,notification明显得多,需要notificationCenter来做为中间交互。而KVO如我们介绍的,设置观察者->处理属性变化,至于中间通知这一环,则隐秘多了,只留一句“交由系统通知”,具体的可参照以上实现过程的剖析。
notification的优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,例如键盘、前后台等系统通知的使用也更显灵活方便。

与delegate的不同

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

delegate一般是一对一,而这两个可以一对多。

KVO应用过程

1:注册观察者,实施监听;

[self.model addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
- observer 指观察者
- keyPath 表示被观察者的属性
- options 决定了提供给观察者change字典中的具体信息有哪些。 【见options解析】
- context 这个参数可以是一个 C指针,也可以是一个 对象引用,它可以作为这个context的唯一标识,也可以提供一些数据给观察者。因为你传进去是啥,回调时候还是回传的还是啥

注册监听,options入参是个枚举,该入参跟监听回调中的change呼应。。并且,以上options入参时候是可以用 | 或运算进行多选的。
例如:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld。。那在change字典中就会包含属性变化前后的值。

2:监听回调

-observeValueForKeyPath:ofObject:change:context:就这一个方法

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    - keyPath:你所观察对象的属性
    - object:你所观察的对象
    - change:你所观察对象属性值的变化
}

注意:通过多options监听属性的时候,例如上,并不是回到一次老值,再回调一次新值,,而是新老值都是在change字典中的。。

3:移除观察者

你可以通过 removeObserver:forKeyPath: 或 removeObserver:forKeyPath:context: 方法来移除一个观察。
注意:如果你的 context 是一个 对象,你必须在移除观察之前持有它的强引用。当移除了观察后,观察者对象再也不会受到这个 keyPath 的通知。

KVO的实现原理

当观察某对象 A 时,KVO 机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性 keyPath 的 setter 方法。setter 方法随后负责通知观察对象属性的改变状况。

参考:

KVC

KVC的理解、应用及其底层原理 https://www.jianshu.com/p/9839ecd75377
iOS开发技巧系列---详解KVC(我告诉你KVC的一切)https://www.jianshu.com/p/9839ecd75377

KVO

原文推荐前往阅读:https://www.jianshu.com/p/e59bb8f59302

相关文章

  • iOS - KVO

    [toc] 参考 KVO KVC 【 iOS--KVO的实现原理与具体应用 】 【 IOS-详解KVO底层实现 】...

  • iOS日记15-KVC

    1.iOS开发技巧系列---详解KVC 2.漫谈 KVC 与 KVO 3.KVC/KVO原理详解及编程指南 关键点...

  • iOS面试 - 收藏集 - 掘金

    KVC 与 KVO 拾遗补缺 - iOS - 掘金KVC 和 KVO 是 Cocoa 框架提供的一个非常强的特性,...

  • KVC 和 KVO

    iOS-KVC和KVO精炼讲解(干货)KVC 和 KVOiOS开发系列--Objective-C之KVC、KVO细...

  • KVC

    iOS 如何使用KVC iOS开发UI篇—Kvc简单介绍 iOS开发系列--Objective-C之KVC、KVO

  • iOS-KVO浅谈

    上一篇:iOS-KVC浅谈 前言:KVO 作为 KVC 的同袍兄弟,功能更强大,聊聊 KVO。 一、KVO 简介 ...

  • iOS基础(四) - KVC和KVO

    iOS观察者模式学习 (1)KVC与KVO简介 KVC KVC(Key-value coding)是一种间接更改对...

  • iOS面试题:KVC的赋值和取值过程是怎样的?KVO原理是什么?

    更多:iOS面试题大全 1、KVC赋值 2、 KVC取值 3、 KVO原理 KVO 是 Objective-C 对...

  • KVC剖析与使用

    KVC与KVO相关面试题 KVC -- Key Value Coding(键值编码) 在iOS开发过程中,允许开发...

  • 4.iOS开发之KVC

    iOS的日常开发中KVC与KVO还是使用率蛮高的,整理一下。KVC和KVO都是基于OC的动态特性和Runtime机...

网友评论

      本文标题:iOS - 《KVC与KVO》

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