美文网首页
KVO的底层实现原理

KVO的底层实现原理

作者: 31313_iOS | 来源:发表于2020-03-27 15:47 被阅读0次

假设有一个类LGLCoder,有一个属性 lglName

@interface LGLCoder : NSObject

@property (nonatomic, strong) NSString  *  lglName;

@end
  • 系统动态创建了一个子类NSKVONotifying_ LGLCoder
  • LGLCoder 的实例对象的 isa 地址指向NSKVONotifying_ LGLCoder
 LGLCoder * lglCode = [[LGLCoder alloc] init];
 NSLog(@"KVO之前 == %p --- %@", object_getClass(lglCode), object_getClass(lglCode));
 [lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
 NSLog(@"KVO之后 == %p ---- %@", object_getClass(lglCode), object_getClass(lglCode));

运行结果

 KVO之前 == 0x10fe17638 --- LGLCoder
 KVO之后 == 0x600003f1de60 ---- NSKVONotifying_LGLCoder
  • 重写了lglName属性的四个方法(setLglName 、class、 dealloc 、 _isKVOA)

通过输出监听以后类的对象的所有方法

///查看对象方法
- (void)lgl_methodNamesOfClass:(Class)cls {
    unsigned int count;
    Method *methodList = class_copyMethodList(cls, &count);
    for (int i = 0; i < count; i++) {
        Method method = methodList[i];
        SEL selector =  method_getName(method);
        NSLog(@"%@",NSStringFromSelector(selector));
    }
    free(methodList);
}
///开启监听
[lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"--------------------------------");
NSLog(@"KVO之后 == %p ---- %@", object_getClass(lglCode), object_getClass(lglCode))
[self lgl_methodNamesOfClass:object_getClass(lglCode)];

运行结果

KVO之后 == 0x6000030d8630 ---- NSKVONotifying_LGLCoder
setLglName 
class
dealloc   
_isKVOA

手动触发 KVO

在设置 lglName 属性时:

  • willChangeValueForKey、didChangeValueForKey会依次被调用。
  • 监听的动作是在didChangeValueForKey中被触发的
#import "LGLCoder.h"

@implementation LGLCoder

- (void)setLglName:(NSString *)lglName {
    NSLog(@"开始调用赋值:lglName = %@",lglName);
    _lglName = lglName;
}

- (void)willChangeValueForKey:(NSString *)key {
    NSLog(@"开始调用 -- willChangeValueForKey");
    [super willChangeValueForKey:key];
    NSLog(@"结束调用 -- willChangeValueForKey");
}

- (void)didChangeValueForKey:(NSString *)key {
    NSLog(@"开始调用 -- didChangeValueForKey");
    [super didChangeValueForKey:key];
    NSLog(@"结束调用 -- didChangeValueForKey");
}

@end

设置监听和赋值

LGLCoder * lglCode = [[LGLCoder alloc] init];
 ///开启监听
[lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
lglCode.lglName = @"lgl";

实现监听结果回调

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"监听到结果改变:%@--%@--%@",keyPath,object,change);
}

运行结果

开始调用 -- willChangeValueForKey
结束调用 -- willChangeValueForKey
开始调用赋值:lglName = lgl
开始调用 -- didChangeValueForKey
监听到结果改变:lglName--<LGLCoder: 0x60000306e670>--{
    kind = 1;
    new = lgl;
}
结束调用 -- didChangeValueForKey

根据上面的运行结果发现,我们可以通过willChangeValueForKey 、didChangeValueForKey来手动触发 KVO。

LGLCoder * lglCode = [[LGLCoder alloc] init];
 ///开启监听
[lglCode addObserver:self forKeyPath:@"lglName" options:NSKeyValueObservingOptionNew context:nil];
[lglCode willChangeValueForKey:@"lglName"];
[lglCode didChangeValueForKey:@"lglName"];

运行结果

开始调用 -- willChangeValueForKey
结束调用 -- willChangeValueForKey
开始调用 -- didChangeValueForKey
监听到结果改变:lglName--<LGLCoder: 0x600000fa0590>--{
    kind = 1;
    new = "<null>";
}
结束调用 -- didChangeValueForKey

这里因为我们没有给lglName赋值(所以new = "<null>";),系统也调用了-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context方法。这样就达到了我们手动触发的目的

相关文章

  • Today面试

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

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

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

  • iOS - KVO

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

  • KVO的底层实现原理

    KVO的底层实现原理
    KVO的定义(Key-Value Observing) ...

  • iOS - 自定义KVO

    之前我们已经了解过了KVO的底层实现原理,不过呢,在我们开始实现自定义KVO之前再来简单回顾下KVO的实现原理 1...

  • iOS开发面试攻略(KVO、KVC、多线程、锁、runloop、

    KVO & KVC KVO用法和底层原理 使用方法:添加观察者,然后怎样实现监听的代理 KVO底层使用了 isa-...

  • 底层原理

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

  • 2018-02-14

    探究KVO的底层实现原理 addObserver:forKeyPath:options:context:各个参数的...

  • 探究KVC的底层实现原理

    慕课网地址 以前写了关于的实现原理的文章,探究KVO的底层实现原理,现在我们也探究一下的底层实现 原理 的全称是K...

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

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

网友评论

      本文标题:KVO的底层实现原理

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