专栏首页正则kvo底层实现 以及自己实现kvo
原创

kvo底层实现 以及自己实现kvo

调用 addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil

系统为我们动态添加了一个NSKVONotifying_+类名的类,因为我们改变对象属性的值是通过setter方法实现了,所以很明显是系统动态生成的NSKVONotifying_ZJPerson类重写了setter方法。

发现方法实现变了,内部调用了系统Foundation框架下的_NSSetObjectValueAndNotify方法。

_NSSetObjectValueAndNotify函数内部实现过程如下

1. `-[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:]:

2. -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:usingBlock:]:

3. [ZJPerson setName:];

4. `NSKeyValueDidChange:

5. `NSKeyValueNotifyObserver:

6. - (void)observeValueForKeyPath:ofObject:change:context

简化成OC的伪代码大致如下:

- (void)setName:(NSString *)name{

_NSSetObjectValueAndNotify();

}

void _NSSetObjectValueAndNotify {

[self willChangeValueForKey:@"name"];

[super setName:name];

[self didChangeValueForKey:@"name"];

}

- (void)didChangeValueForKey:(NSString *)key{

[observe observeValueForKeyPath:key ofObject:self change:nil context:nil];

}

可以利用runtime方法打印一下方法列表:

unsigned int count;

Method *methods = class_copyMethodList(object_getClass(self.person), &count);

for (NSInteger index = 0; index < count; index++) {

   Method method = methods[index];

   NSString *methodStr = NSStringFromSelector(method_getName(method));

NSLog(@"%@\n", methodStr);

}

2018-05-20 08:57:07.883400+0800 KVO[35888:3218908] setName:

2018-05-20 08:57:07.883571+0800 KVO[35888:3218908] class

2018-05-20 08:57:07.883676+0800 KVO[35888:3218908] dealloc

2018-05-20 08:57:07.883793+0800 KVO[35888:3218908] _isKVOA

简单分析下重写这些方法的作用:

class:重写这个方法,是为了伪装苹果自动为我们生成的中间类。

dealloc:应该是处理对象销毁之前的一些收尾工作

_isKVOA:告诉系统使用了kvo

自己动手写一个KVO

KVO底层实现还是很复杂的,下面我只是简单的写下实现过程:

  • 因为它是一个非正式协议,给NSObject新建一个Category,NSObject+kvo.h,添加监听方法:

.h

#import <Foundation/Foundation.h>

@interface NSObject (kvo)

- (void)zj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;

@end

.m

#import "NSObject+kvo.h"

#import <objc/runtime.h>

#import <objc/message.h>

@implementation NSObject (kvo)

- (void)zj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{

//动态添加一个类

    NSString *originClassName = NSStringFromClass([self class]);

    NSString *newClassName = [@"ZJKVO_" stringByAppendingString:originClassName];

const char *newName = [newClassName UTF8String];

// 继承自当前类,创建一个子类

    Class kvoClass = objc_allocateClassPair([self class], newName, 0);

// 添加setter方法

class_addMethod(kvoClass, @selector(setName:), (IMP)setName, "v@:@");

//注册新添加的这个类

objc_registerClassPair(kvoClass);

// 修改isa指针,由ZJPerson指向ZJKVO_Person

object_setClass(self, kvoClass);

// 保存观察者属性到当前类中

objc_setAssociatedObject(self, (__bridge const void *)@"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

#pragma mark - 重写父类方法

void setName(id self, SEL _cmd, NSString *name) {

// 保存当前KVO的类

    Class kvoClass = [self class];

// 将self的isa指针指向父类ZJPerson,调用父类setter方法

object_setClass(self, class_getSuperclass([self class]));

// 调用父类setter方法,重新复制

objc_msgSend(self, @selector(setName:), name);

// 取出ZJKVO_Person观察者

    id objc = objc_getAssociatedObject(self, (__bridge const void *)@"observer");

// 通知观察者,执行通知方法

objc_msgSend(objc, @selector(observeValueForKeyPath:ofObject:change:context:), name, self, nil, name);

// 重新修改为ZJKVO_Person类

object_setClass(self, kvoClass);

}

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • KVO详解及底层实现

    czjwarrior
  • # iOS中的KVO底层实现

    KVO是Key-Value-Observer的缩写,使用的是观察者模式。底层实现机制都是isa-swizzing,就是在底层调用object_setClass函...

    Haley_Wong
  • iOS底层原理总结 - 探寻KVO本质

    xx_Cc
  • 详解:RxSwift-KVO底层探索(上)

    下面我们开始分析,首先感谢苹果开源精神,在Github可以直接下载,我们通过 Swift 源码展开分析

    猿_人类
  • KVO实现原理

    KVO(key value observing)键值监听是我们在开发中常使用的用于监听特定对象属性值变化的方法,常用于监听数据模型的变化

    猿_人类
  • KVO、Delegate、Notification 区别及相关使用场景你要知道的KVC、KVO、Delegate、Notification都在这里

    你要知道的KVC、KVO、Delegate、Notification都在这里 转载请注明出处 https://cloud.tencent.com/develop...

    WWWWDotPNG
  • ios KVO及实现原理

    概述 KVO全称KeyValueObserving,是苹果提供的一套事件通知机制。允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的实现...

    赵哥窟
  • iOS开发·KVO用法,原理与底层实现: runtime模拟实现KVO监听机制(Blcok及Delgate方式)

    KVO 是 Objective-C 对 观察者模式(Observer Pattern)的实现。当被观察对象的某个属性发生更改时,观察者对象会获得通知。有意思的是...

    陈满iOS
  • ios KVO 官方文档学习

    When an observer is registered for an attribute of an object the isa pointer of ...

    onety码生
  • KVO 正确使用姿势进阶及底层实现你要知道的KVC、KVO、Delegate、Notification都在这里

    你要知道的KVC、KVO、Delegate、Notification都在这里 转载请注明出处 https://cloud.tencent.com/develop...

    WWWWDotPNG
  • OC观察者模式之KVO的使用与思考

    无论用哪种语言进行软件开发,我们都会接触到设计模式,个人认为设计模式存在的意义在于:在某些需求下,采用适合的设计模式,使代码结构合理,从而提高代码的可读性、可扩...

    yuanyi928
  • iOS 知识点回顾(一)

    且行且珍惜_iOS
  • KVO详解(一)

    我在之前的文章iOS开发中的设计模式--观察者模式中有介绍过KVO的简单使用,大家可以先去了解一下。今天呢,我们来详细分析下KVO。

    拉维
  • 编码篇-KVO的使用大全

    设置类的A属性依赖于B、C属性时,对类的A属性进行观察,当B、C属性发生改变时,也会触发对A的观察者方法。

    進无尽
  • RAC(ReactiveCocoa)介绍(八)——KVO销毁

    上一篇探究了RAC的销毁机制,既然说到销毁,就不得不说下RAC中的KVO销毁。 在RAC中使用KVO时,仅需一行代码,即可完成对指定对象的属性变化值监听,而且...

    我只不过是出来写写代码
  • iOS - 关于 KVO 的一些总结

    KVO使用三部曲:添加/注册KVO监听、实现监听方法以接收属性改变通知、 移除KVO监听。

    师大小海腾
  • 程序员面试时这样介绍自己的项目经验,成功率能达到98.99%

    声明:面试是对自我审视的一种过程,面试题和iOS程序员本身技术水平没任何关联,无论你能否全部答出,都不要对自己产生任何正面或消极的评价!(面试题均来自群成员提供...

    java爱好者
  • 探究ReactiveCocoa 底层KVO封装流程

    原文作者:溪浣双鲤 https://www.jianshu.com/p/51758229b4a5

    iOSSir
  • 探究ReactiveCocoa 底层KVO封装流程

    但是RACKVO只是用了非常简单的一段代码就实现了以上的这三个步骤,去掉了胶水代码,真正的做到了面向业务开发,那它是怎么实现的呢,接下来我们来一层层分析

    iOSSir

扫码关注云+社区

领取腾讯云代金券