美文网首页
深入了解 KVO

深入了解 KVO

作者: _一叶孤帆 | 来源:发表于2021-02-24 23:56 被阅读0次

含义

KVO 全程是 Key-Value Observing,又称 键值监听, 可以用于监听某个对象属性值的改变。

官方文档

基本使用

注册键值观察

示例:

  1. 新建一个 person
    image.png
  1. 使用 KVO 来监听 person 类中 age 的变化
image.png

输出结果

2021-02-24 21:44:37.344268+0800 KVO[43609:799884] 监听到 <Person: 0x6000000cc320> 的 age 属性值改了--- {
    kind = 1;
    new = 20;
    old = 10;
}--- 我是context

本质分析

  1. 构建一个 p2 对象
  2. 点击屏幕改变其 age 值
  3. 断点两个对象并打印其 isa

结果验证

(lldb) po self.p.isa
NSKVONotifying_Person

  Fix-it applied, fixed expression was: 
    self.p->isa
(lldb) po self.p1.isa
Person

  Fix-it applied, fixed expression was: 
    self.p1->isa
(lldb) 

可以发现两个对象的 isa 并不相同,而实例对象的 isa 指向其类对象,所以我们可以发送两个对象的类对象并不相同,p 对象被指向了一个名为 NSKVONotifying_Person 的类。

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
    frame #0: 0x000000010f0edf4f KVO`-[Person setAge:](self=0x0000600000c446d0, _cmd="setAge:", age=20) at Person.m:14:12
  * frame #1: 0x00007fff207c1749 Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 646
    frame #2: 0x00007fff207c200b Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 68
    frame #3: 0x00007fff207bb3c1 Foundation`_NSSetIntValueAndNotify + 266
    frame #4: 0x000000010f0eda6e KVO`-[ViewController touchesBegan:withEvent:](self=0x00007fe8d7507540, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x0000600003b4c240) at ViewController.m:37:12
    frame #5: 0x00007fff246c4823 UIKitCore`forwardTouchMethod + 321
    frame #6: 0x00007fff246c46d1 UIKitCore`-[UIResponder touchesBegan:withEvent:] + 49
    frame #7: 0x00007fff246d36c9 UIKitCore`-[UIWindow _sendTouchesForEvent:] + 622
    frame #8: 0x00007fff246d57db UIKitCore`-[UIWindow sendEvent:] + 4774
    frame #9: 0x00007fff246af57a UIKitCore`-[UIApplication sendEvent:] + 633
    frame #10: 0x00007fff24740000 UIKitCore`__processEventQueue + 13895
    frame #11: 0x00007fff24736973 UIKitCore`__eventFetcherSourceCallback + 104
    frame #12: 0x00007fff2038f38a CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #13: 0x00007fff2038f282 CoreFoundation`__CFRunLoopDoSource0 + 180
    frame #14: 0x00007fff2038e764 CoreFoundation`__CFRunLoopDoSources0 + 248
    frame #15: 0x00007fff20388f2f CoreFoundation`__CFRunLoopRun + 878
    frame #16: 0x00007fff203886d6 CoreFoundation`CFRunLoopRunSpecific + 567
    frame #17: 0x00007fff2bededb3 GraphicsServices`GSEventRunModal + 139
    frame #18: 0x00007fff24690e0b UIKitCore`-[UIApplication _run] + 912
    frame #19: 0x00007fff24695cbc UIKitCore`UIApplicationMain + 101
    frame #20: 0x000000010f0edff2 KVO`main(argc=1, argv=0x00007ffee0b11ce0) at main.m:17:12
    frame #21: 0x00007fff202593e9 libdyld.dylib`start + 1
    
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x000000010f0edb22 KVO`-[ViewController observeValueForKeyPath:ofObject:change:context:](self=0x00007fe8d7507540, _cmd="observeValueForKeyPath:ofObject:change:context:", keyPath=@"age", object=0x0000600000c446d0, change=0x0000600001b01dc0, context=@"我是context") at ViewController.m:45:63
    frame #1: 0x00007fff207be6f4 Foundation`NSKeyValueNotifyObserver + 329
    frame #2: 0x00007fff207c1e28 Foundation`NSKeyValueDidChange + 439
    frame #3: 0x00007fff207c17a8 Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 741
    frame #4: 0x00007fff207c200b Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 68
    frame #5: 0x00007fff207bb3c1 Foundation`_NSSetIntValueAndNotify + 266
    frame #6: 0x000000010f0eda6e KVO`-[ViewController touchesBegan:withEvent:](self=0x00007fe8d7507540, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x0000600003b4c240) at ViewController.m:37:12
    frame #7: 0x00007fff246c4823 UIKitCore`forwardTouchMethod + 321
    frame #8: 0x00007fff246c46d1 UIKitCore`-[UIResponder touchesBegan:withEvent:] + 49
    frame #9: 0x00007fff246d36c9 UIKitCore`-[UIWindow _sendTouchesForEvent:] + 622
    frame #10: 0x00007fff246d57db UIKitCore`-[UIWindow sendEvent:] + 4774
    frame #11: 0x00007fff246af57a UIKitCore`-[UIApplication sendEvent:] + 633
    frame #12: 0x00007fff24740000 UIKitCore`__processEventQueue + 13895
    frame #13: 0x00007fff24736973 UIKitCore`__eventFetcherSourceCallback + 104
    frame #14: 0x00007fff2038f38a CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #15: 0x00007fff2038f282 CoreFoundation`__CFRunLoopDoSource0 + 180
    frame #16: 0x00007fff2038e764 CoreFoundation`__CFRunLoopDoSources0 + 248
    frame #17: 0x00007fff20388f2f CoreFoundation`__CFRunLoopRun + 878
    frame #18: 0x00007fff203886d6 CoreFoundation`CFRunLoopRunSpecific + 567
    frame #19: 0x00007fff2bededb3 GraphicsServices`GSEventRunModal + 139
    frame #20: 0x00007fff24690e0b UIKitCore`-[UIApplication _run] + 912
    frame #21: 0x00007fff24695cbc UIKitCore`UIApplicationMain + 101
    frame #22: 0x000000010f0edff2 KVO`main(argc=1, argv=0x00007ffee0b11ce0) at main.m:17:12
    frame #23: 0x00007fff202593e9 libdyld.dylib`start + 1

可以看出会首先调用 Fountion 中的 _NSSetIntValueAndNotify,然后在内部又调用了父类的 setAge

动态类分析

分析其中的方法

NSKVONotifying_Person setAge:,class,dealloc,_isKVOA,

修改成员变量

不会触发 kvo, 因为不会调用 set 方法。

结论

所以本质就是为我们动态生成了一个类,切重写了 set 方法 并将 set 方法内部绑定调用了 Fountion 中的函数

相关文章

  • 深入了解 KVO

    含义 KVO 全程是 Key-Value Observing,又称 键值监听, 可以用于监听某个对象属性值的改变。...

  • KVO的原理

    KVO基本原理: KVO深入原理: 适用于:

  • swift中KVO和属性观察器

    开篇提醒:OC中的KVO及其KVO的基础知识可参见:深入runtime探究KVO Swift中,原本没有KVO模式...

  • iOS 深入了解KVO 本质/使用

    项目 Demo 下载[https://github.com/liuyaozong1/LYZKVODemo.git]...

  • 理解KVO

    相信KVO对大家来说都不陌生,即使你没有使用过,基本也都曾了解过,听说过。这篇文章作者就带大家来深入研究一下KVO...

  • KVO 解析

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

  • 探究KVO本质

    看了一些资料,对OC更加深入了解,记录总结一下。KVO:key-value-boserver,键-值-监听。主要是...

  • iOS runtime自定义实现KVO

    1、了解KVO 打印结果: 2、自定义实现KVO .h .m

  • iOS底层原理汇 - 探索KVO本质

    问题 iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?) 如何手动触发KVO ? 首先需要了解KVO...

  • 1.iOS开发之--KVO详解

    如果你从事iOS开发,对于KVO肯定不陌生.今天写了这篇文章,让我们进一步了解KVO,我们从下图几个部分了解KVO...

网友评论

      本文标题:深入了解 KVO

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