KVO

作者: CB7D | 来源:发表于2019-03-31 17:40 被阅读0次

原文链接

Key-Value Observing 键值观察 ,是一种设计模式观察者模式的实现

官方定义

键值观察提供了一种机制,允许对象通知其他对象的特定属性的更改。它对应用程序中模型和控制器层之间的通信特别有用。(在OS X中,控制器层绑定技术严重依赖于键值观察。)控制器对象通常观察模型对象的属性,视图对象通过控制器观察模型对象的属性。然而,另外,模型对象可以观察其他模型对象(通常用于确定从属值何时改变)或甚至自身(再次确定从属值何时改变)。

先看下使用KVO的姿势

Xcode -> New -> MacOS -> CommandLine 新建工程,创建Person类

Person.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject

@property (nonatomic ,copy) NSString *name;

@property (nonatomic ,assign) NSUInteger age;

@property (nonatomic ,copy) NSArray<Person *> *friends;

@end

NS_ASSUME_NONNULL_END

Person.m

#import "Person.h"

@implementation Person

- (instancetype)init {
    
    self = [super init];
    
    if (self) {
        _name = @"";
        _age = 0;
        _friends = @[];
    }
    
    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    
    // 当收到通知的时候打印观察的对象,旧值和新值
    NSLog(@"\nReceving ObserveValueChanged \nObject: %@ OldValue: %@, NewValue: %@",object, change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]);
    change[@"new"]);
}

// 重写以便打印对象的属性
- (NSString *)description {
    
    return [NSString stringWithFormat:@"- name: %@, age: %ld, friends: %@",self.name, self.age, self.friends];
}

@end

打开main.m,创建Alice和Bob,设置Bob观察Alice的age属性

Person *Alice = Person.new;
Alice.name = @"Alice";
Alice.age = 18;

Person *Bob = Person.new;
Bob.name = @"Bob";
Bob.age = 28;


[Alice addObserver:Bob forKeyPath:@"age" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:PersonChangeContext];

Alice.age = 100;

[Alice removeObserver:Bob forKeyPath:@"age"];

Alice.age = 200;

可以看到控制台输出了一次Alice的age属性的前后变化.

其中,NSKeyValueObservingOptions 有以下几个选项,可以使用 | 符号组合使用

  • NSKeyValueObservingOptionNew // 收到通知时change字典将包含新值
  • NSKeyValueObservingOptionOld // 收到通知时change字典将包含旧值
  • NSKeyValueObservingOptionInitial // 在addObserver时会发送通知,change字典将包含初始值
  • NSKeyValueObservingOptionPrior // 在所观察keyPath改变之前将收到通知

change字典的key值在这里

FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeKindKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeNewKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeOldKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeIndexesKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeNotificationIsPriorKey 

KVO的使用场景有很多,比如Person拥有一个account属性,person需要获取account的变化该如何处理呢,轮训或许是个办法,但是无疑效率低下,而且很不安全,更合理的办法就是使用KVO观察account,在account发生变化时更新。

原理

现在我们已经知其然了,但是还不知其所以然。

先说结论

  1. 系统通过runtime生成继承与被观察者的新类(NSKVONotifying_Person),对原对象进行isa-swizzing(isa混写)
  2. 根据KVC(键值编码)对对象的keypath进行hock
  3. 在将要对属性进行赋值操作时发送通知

如何证明上述结论呢,上代码!

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "Person.h"

static void *PersonChangeContext = &PersonChangeContext;

int main(int argc, const char * argv[]) {
    @autoreleasepool {        
        
        Person *Alice = Person.new;
        Alice.name = @"Alice";
        Alice.age = 18;
        
        Person *Bob = Person.new;
        Bob.name = @"Bob";
        Bob.age = 28;
        
        
        Class cls0 = object_getClass(Alice);
        
        [Alice addObserver:Bob forKeyPath:@"age" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:PersonChangeContext];
        
        Alice.age = 100;
        
        Class cls1 = object_getClass(Alice);
        
        NSLog(@"%@ %@",cls0,cls1);
        
    }
    return 0;
}
  1. 首先引入runtime,这样我们可以打印isa所指向的真实的类,
  2. 在向Alice添加观察者之前,先获取Class
  3. 在向Alice添加观察者之后,获取Class
Person NSKVONotifying_Person

可以看到输出确实如此

这就是KVO的核心思路了,关于KVC请看这里.

相关文章

  • iOS原理篇(一): KVO实现原理

    KVO实现原理 什么是 KVO KVO 基本使用 KVO 的本质 总结 一 、 什么是KVO KVO(Key-Va...

  • 04. KVO使用,原理,本质

    问题 KVO日常使用 KVO原理(KVO本质是什么) 如何手动触发KVO 直接修改成员变量会触发KVO吗 KVO图...

  • 20.iOS底层学习之KVO 原理

    本篇提纲1、KVO简介;2、KVO的使用;3、KVO的一些细节;4、KVO的底层原理; KVO简介 KVO全称Ke...

  • 深入理解KVO

    iOS | KVO | Objective-C KVO的本质是什么,如何手动触发KVO? 1.什么是KVO KVO...

  • OC语法:KVO的底层实现

    一、KVO是什么二、怎么使用KVO三、KVO的底层实现四、KVO常见面试题 一、KVO是什么 KVO全称Key-V...

  • KVO基本使用

    分三部分解释KVO一.KVO基本使用二.KVO原理解析三.自定义实现KVO 一、KVO基本使用 使用KVO,能够非...

  • KVO 解析

    KVO解析(一) —— 基本了解KVO解析(二) —— 一个简单的KVO实现KVO解析(三) —— KVO合规性K...

  • KVO

    目录 1. KVO的使用1.1 KVO基本使用方法1.2 KVO手动触发模式1.3 KVO属性依赖1.4 KVO容...

  • OC语言之KVO与KVC

    KVO 什么是KVO? KVO 是 Key-value observing(键值观察)的缩写。 KVO是Objec...

  • 可能碰到的iOS笔试面试题(7)--KVO-KVC

    KVC-KVO KVC的底层实现? KVO的底层实现? 什么是KVO和KVC? KVO的缺陷? KVO是一个对象能...

网友评论

    本文标题:KVO

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