ios KVO的实现原理

首先给大家介绍一下KVO的使用场景:当某个对象的某个属性改变的时候,需要我们做出相应的处理事件。比如我们自定义下拉刷新,那么我们是如何得知用户要进行的下拉刷新数据操作呢,我们可以监听控件的frame,通过用户下拉该控件的时候,会修改该控件的frame.y属性,我们使用KVO监听这个属性。当这个属性的y值在某个范围,我们认为是下拉刷新操作。我们可以去进行数据请求。因为现在下拉刷新的第三方框架有很多,所以很少有人关注下拉刷新的实现原理。 又比如,我们经常使用的网络请求的第三方AFN,它内部监听网络下载进度也是通过KVO实现的。无凭无据,我们来看代码

fractionCompleted则是self.downloadProgress对象代表下载进度的属性

等等。所以KVO的使用之处还是比较多的。那么,我们就看看KVO实现的原理是什么样子的,如何实现对属性的监听的。

给大家介绍一下官方的回答:当某个类的对象一次被观察时,系统就会在运行时动态的创建该类的一个派生类(子类),在这个派生类重写被观察属性的setter方法,派生类在被重写的setter方法实现真正的通知机制。派生类重写了class方法以欺骗外部调用者它就是起初监听的那个类。然后系统将这个对象的isa指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对setter的调用就会调用重写的setter,从而激活键值通知机制。此外,派生类还重写了dealloc方法来释放资源。

不知道看完这段话的你,头脑还是否清醒。下面我们一句一句来解释:

创建一个Person类,定义一个age属性,然后我们监听age属性

@interface Person : NSObject

@property (nonatomic , assign) int age;

@end
@implementation ViewController {

    Person *_p;

}

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建Person对象
    _p = [[Person alloc] init];

    //给Person对象的age属性添加监听
    [_p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

    //修改p的age属性
    _p.age = 10;

}

//KVO回调方法,
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {

    NSLog(@"%@对象的%@属性变化了%@",object,keyPath,change);

}

//控制器销毁的时候 移除KVO
- (void)dealloc {

    [_p removeObserver:self forKeyPath:@"age"];

}

这个时候,会打印输出

这是KVO使用的步骤。

接下来,我们理解一下这段代码。

1.创建一个Person类的实例对象P

2.给对象P的age属性添加键值监听

3.修改对象P的age属性

4.实现KVO的回调方法

5.移除KVO监听

从输出结果来看,我们是可以正常监听到P的age属性的变化的。

根据官方的解释:当某个类的对象一次被观察时,系统就会在运行时动态的创建该类的一个派生类(子类)

那么,我们看一下这到底是一个什么样的子类:

看断点断的地方,打印这个结果的时候我还没有对对象P进行KVO监听。有的人会问,objc_getClass()是什么,objc开头的函数基本都是runtime里面的函数。所以这是动态获取对象的类型。

当对对象P的age属性进行监听以后,对象P的真实类型变为了NSKVONotifying_Person。那么,为什么po _p 还是<Person>类型的呢,这就是‘派生类重写了class方法以欺骗外部调用者它就是起初监听的那个类’。

接下来,我们再一步步理解。既然有了这个子类了,我们再这个子类的setter方法里面动动手脚,是不是就可以出发KVO的回调了,就会输出监听的结果呢?那么,我们如何让Person类型的P对象,去执行NSKVONotifying_Person类里面的setter方法呢?系统将这个对象(P)的isa指针指向这个新诞生的派生类(NSKVONotifying_Person)。不知道大家对isa指针了解多少?OC所有的类都有一个共同的属性,那就是isa。有图有真相:

那么。这个isa指针是干什么用的呢。

isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

所以,只要我们修改了isa指针指向的类。就会去它指向的类里面寻找setter方法,也就是会去(NSKVONotifying_Person)类里面寻找setter方法,这个时候我们再NSKVONotifying_Person类的setter方法里面做些事情,从而触发KVO的回调方法,也就是

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {

    NSLog(@"%@对象的%@属性变化了%@",object,keyPath,change);

}

是不是就成功了,接下来介绍,我们再setter方法里面具体怎么做,才能触发这个方法呢?

#import "Person.h"

@implementation Person

- (void)test {

    [self willChangeValueForKey:@"age"];

    [self didChangeValueForKey:@"age"];

}

@end

给Person类添加一个test方法。这个时候,我修改ViewController里面的代码

@implementation ViewController {

    Person *_p;

}

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建Person对象
    _p = [[Person alloc] init];

    //给Person对象的age属性添加监听
    [_p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

//调用test方法
    [_p test];

}

//KVO回调方法,
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {

    NSLog(@"%@对象的%@属性变化了%@",object,keyPath,change);

}

//控制器销毁的时候 移除KVO
- (void)dealloc {

    [_p removeObserver:self forKeyPath:@"age"];

}

这个时候,运行代码,你会发现也会触发KVO的回调用法。可是我根本没有改变age属性的值。怎么会触发呢。归根究底,问题出现在test的实现方法里面,也就是

[self willChangeValueForKey:@"age"];

[self didChangeValueForKey:@"age"];

这两句代码是触发KVO的回调方法的关键了。所以,我们只要在NSKVONotifying_Person类里面重写setAge方法。就可以实现KVO监听了。这也就是所谓的“在这个派生类重写被观察属性的setter方法,派生类在被重写的setter方法实现真正的通知机制”;

- (void)setAge:(int)age {

    [self willChangeValueForKey:@"age"];

    self.age = age;

    [self didChangeValueForKey:@"age"];

}

看完这篇文章,如果大家有不理解的地方,可以留言一起讨论。谢谢。

时间: 2024-11-08 19:18:10

ios KVO的实现原理的相关文章

iOS KVO概述

iOS KVO概述 面试中经常会被问到:什么是KVO?这个问题既然出现概率这么大,那么我们就来详细讲一讲到底什么是KVO.下次再有面试官问你的时候,你就可以娓娓道来,以彰显高逼格 概述 问:什么是KVO? 答:KVO是Key-Value Observing的缩写.它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了. 如果你能这样回答,面试官一定不会说你错的,这就是KVO的原理.但是如果你能说出KVO

KVO内部实现原理

// // ViewController.m // KVO内部实现原理 // // Created by sw on 15/4/13. // Copyright © 2015年 sw. All rights reserved. // #import "ViewController.h" #import "Person.h" @interface ViewController () @end @implementation ViewController - (void

KVO的实现原理

摘自:iOS--KVO的实现原理与具体应用 1 KVO是什么? KVO是Objective-C对观察者模式的一种实现,另外一种是通知机制(notification) KVO提供一种机制,指定一个被观察对象(例如A类),当对象的某个属性(例如A中的字符串name)发生更改时,对象会获得通知,并做出相应的处理. 在MVC设计架构下的项目,KVO机制很适合实现model模型和view视图之间的通讯. 例如:代码中,在模型类A创建属性数据,在控制器中创建观察者,一旦属性数据发生改变,观察者就会收到通知,

IOS系统推送原理

IOS推送大致原理如下图 1.Provider:就是为指定IOS设备应用程序提供Push的服务器,(如果IOS设备的应用程序是客户端的话,那么Provider可以理解为服务端[消息的发起者]): 2.APNS:Apple Push Notification Service[苹果消息推送服务器]: 3.iPhone:用来接收APNS下发下来的消息: 4.Client App:IOS设备上的应用程序,用来接收iphone传递APNS下发的消息到制定的一个客户端 app[消息的最终响应者]: 上图可以

iOS ---- KVO的内部实现原理

Key-Value Observing (KVO) KVO:当指定的对象的属性被修改了,允许对象接收到通知的机制.   [persion addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld |NSKeyValueObservingOptionNew context:nil]; 只要当前类中 age 这个属性发生的变化都会触发到以下的方法 - (void)observeValueForKeyPat

iOS KVO的原理

KVO(Key Value Observing),是观察者模式在Foundation中的实现. KVO的原理 简而言之就是: 1.当一个object有观察者时,动态创建这个object的类的子类 2.对于每个被观察的property,重写其set方法 3.在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者 4.当一个property没有观察者时,删除重写的方法 5.当没有observer观察任何一个property时

KVO底层实现原理,仿写KVO

这篇文章简单介绍苹果的KVO底层是怎么实现的,自己仿照KVO的底层实现,写一个自己的KVO监听 #pragma mark--KVO底层实现 第一步:新建一个Person类继承NSObject Person.h #import <Foundation/Foundation.h> @interface Person : NSObject //字符串类型的属性name @property (nonatomic, strong) NSString *name; @end Person.m #impor

iOS KVO详解

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

【如何快速的开发一个完整的iOS直播app】(原理篇)

一.个人见解(直播难与易) 直播难:个人认为要想把直播从零开始做出来,绝对是牛逼中的牛逼,大牛中的大牛,因为直播中运用到的技术难点非常之多,视频/音频处理,图形处理,视频/音频压缩,CDN分发,即时通讯等技术,每一个技术都够你学几年的. 直播易:已经有各个领域的大牛,封装好了许多牛逼的框架,我们只需要用别人写好的框架,就能快速的搭建一个直播app,也就是传说中的站在大牛肩膀上编程. 二.了解直播 热门直播产品 映客,斗鱼,熊猫,虎牙,花椒等等 直播效果图 直播效果.jpeg 1.一个完整直播ap