美文网首页
iOS KVO 底层实现原理探索

iOS KVO 底层实现原理探索

作者: 032c6843a285 | 来源:发表于2020-11-13 10:23 被阅读0次

⚠️ KVO (Key-Value Observing) 认识:

\color{#FF0000}{KVO} 是Objective-C对观察者设计模式的一种实现,它提供一种机制,指定一个被观察对象(如A类),当对象中的某个属性发生变化的时候,对象就会接收到通知,并作出相应的处理。在MVC设计架构下的项目,KVO机制很适合实现mode模型和view视图之间的通讯。例如:代码中,在模型类A创建属性数据,在控制器中创建观察者,一旦属性数据发生改变就收到观察者收到通知,通过KVO再在控制器使用回调方法处理实现视图B的更新


⚠️ KVO底层实现原理

  • 1 KVO是基于runtime机制实现的
  • 2 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制
    3 如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
  • 4 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
  • 5 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
  • 6 补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类

⚠️ 代码验证

  • 首先创建一个 “Person” 模型文件 并且声明一个属性 name
@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@end
  • 在控制器中初始化该类的实例对象person,进行相关KVO常用三部曲
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.person = [[Person alloc]init];
    [self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
 
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    self.person.name = @"测试 peron 属性";
}


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    
    NSLog(@"改变了这个属性。%@ ",change);
    
    
}
- (void)dealloc{
 
    [self.person removeObserver:self forKeyPath:@"name"];
    
}

以上就是相关的环境搭建,相信只要接触iOS开发的同学都知道怎么使用KVO

从打印结果看

2020-11-13 10:16:37.142420+0800 KVODemo[8216:6066339] 改变了这个属性。{
    kind = 1;
    new = "\U6d4b\U8bd5 peron \U5c5e\U6027";
} 

NSKeyValueChangeSetting = 1, 也就是属性的setter方法,
NSKeyValueChangeInsertion = 2,是集合类型的添加方法,NSKeyValueChangeRemoval = 3,是集合的移除操作,NSKeyValueChangeReplacement = 4,是可变集合类型的元素替换。

typedef NS_ENUM(NSUInteger, NSKeyValueChange) {
    NSKeyValueChangeSetting = 1,
    NSKeyValueChangeInsertion = 2,
    NSKeyValueChangeRemoval = 3,
    NSKeyValueChangeReplacement = 4,
};
  • 1.如何验证派生类NSKVONotifying_Person的存在?
    我们进行断点调试;在程序刚刚初始化self.person的时候以及添加观察者的时候进行断点调试,看看类的信息变化,通过object_getClassName输出当前类信息
WeChat880dea9d43ec54a24c56a0f36a0cd7f8.png
  • 2 如何验证通过willChangeValueForKey 和 didChangevlueForKey 来改变监听属性的值,从而达到修改的目的?
    这一步其实很好验证的,我们在实现的类中重写+(BOOL)accessInstanceVariablesDirectly 使其返回值为NO,这样如果我们不手动实现以上的两个改变属性值得方法,我们是打印不出任何值得改变的,然而我们手动实现这两个方法时
-(void)setName:(NSString *)name
{
    [self willChangeValueForKey:name];
    _name = [name copy];
    [self didChangeValueForKey:name];
    
}

+(BOOL)accessInstanceVariablesDirectly
{
    return NO;
}

此时控制台打印的内容和我们监听的一抹一样。这就是通过willChangeValueForKey 和 didChangevlueForKey改变属性值得过程;


  • 3 如何验证通知结束后isa指向返回原类,派生类NSKVONotifying_Person释放
    我们在程序该控制器销毁的时候打印相关的结果,断点调试
image.png
(lldb) po object_getClassName(self.person)
"Person"

相关文章

  • iOS - KVO

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

  • IOS底层(三) KVO底层实现原理

    @[TOC](IOS底层(三) KVO底层实现原理 ) 一,KVO简述 KVO的全称 Key-Value Obse...

  • 底层原理

    iOS底层原理总结 - Category的本质 KVO详解及底层实现青少年一定要读的KVO指南 iOS 底层解析w...

  • iOS KVO 底层实现原理探索

    ⚠️ KVO (Key-Value Observing) 认识: 是Objective-C对观察者设计模式的一种实...

  • 关于KVO底层Runtime实现的那点事

    有很多公司iOS面试都会被问到KVO底层的实现。网上也有很多篇关于KVO的底层原理,但是都是用willChange...

  • Today面试

    Runloop 底层原理Kvo 底层原理ARC 底层原理 如何实现GCD 底层原理Block 底层原理Aut...

  • iOS底层原理探索—内存管理(一)

    探索底层原理,积累从点滴做起 往期回顾 iOS底层原理探索 — OC对象的本质 iOS底层原理探索 — class...

  • iOS 底层探索:KVO 底层原理

    iOS 底层探索: 学习大纲 OC篇[/p/9d73ee7aae64] 前言 在Key-Value Observi...

  • iOS-底层原理21-KVO(下)

    iOS-底层原理21-KVO(下) 《iOS底层原理文章汇总》[https://www.jianshu.com/p...

  • iOS 探索KVO底层原理

    KVO底层原理 记 上一篇文章中说到,KVO监听成员变量无法收到回调。先验证一下是不是对的。 1.创建一个Pers...

网友评论

      本文标题:iOS KVO 底层实现原理探索

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