Object-C中KVO探索

作者: zwwuchn | 来源:发表于2019-08-01 10:22 被阅读15次

什么是KVO

KVO(Key-Value Observing),俗称键值监听。它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。

监听方法

- (void)addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context;
  • observer: 观察者,也就是KVO通知的订阅者
  • keyPath: 描述将要观察的属性,相对于被观察者
  • options: KVO的一些属性配置;有四个选项
    1. NSKeyValueObservingOptionNew:change字典包括改变后的值
    2. NSKeyValueObservingOptionOld:change字典包括改变前的值
    3. NSKeyValueObservingOptionInitial:注册后立刻触发KVO通知
    4. NSKeyValueObservingOptionPrior:值改变前是否也要通知
  • context: 上下文,这个会传递到订阅着的函数中,用来区分消息

移除监听

- (void)removeObserver:(NSObject*)anObserver forKeyPath:(NSString*)keyPath;

- (void)removeObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath context:(void*)context;

回调监听

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context;

KVO使用步骤

  1. 注册,指定被观察者的属性
  2. 实现回调方法
  3. 移除观察

代码展示

@interfacePerson:NSObject

@property(nonatomic,assign)NSIntegerage;

@end

@implementationPerson

@end
self.person1 = [[Person alloc]init];

self.person2 = [[Person alloc]init];

NSLog(@"监听前%@ --- %@",object_getClass(self.person1),object_getClass(self.person2));

NSKeyValueObservingOptionsoptions =NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;

[self.person2 addObserver:selfforKeyPath:@"age"options:options context:nil];

self.person2.age =20;

NSLog(@"监听后%@ --- %@",object_getClass(self.person1),object_getClass(self.person2));


[self.person2 removeObserver:selfforKeyPath:@"age"];

打印结果:

KVODemo[2879:697131] 监听前Person --- Person

KVODemo[2879:697131] 监听后NSKVONotifying_Person--- Person

监听前

  • self.person1的isa指向Person
  • self.person2的isa指向Person

监听后

  • self.person1的isa指向NSKVONotifying_Person
  • self.person2的isa指向Person

RuntimeAPI动态生成一个NSKVONotifying_Person,并且让instance对象的isa指向这个全新的NSKVONotifying_Person

打印NSKVONotifying_Person内部方法

我们需要用到这个分类DLIntrospection已经有大神帮我们封装好了

+ (NSArray*)classes;

+ (NSArray*)properties;

+ (NSArray*)instanceVariables;

+ (NSArray*)classMethods;

+ (NSArray*)instanceMethods;

+ (NSArray*)protocols;

+ (NSDictionary*)descriptionForProtocol:(Protocol *)proto;

+ (NSString*)parentClassHierarchy;

断点调试结果

KVO[23897:840022] 监听前Person --- Person

(lldb) po [object_getClass(self.person1) instanceMethods]

<__NSArrayI0x604000429720>(

- (void)setAge:(q)arg0 ,

- (q)age

)

(lldb) po [object_getClass(self.person2) instanceMethods]

<__NSArrayI0x600000245ca0>(

- (void)setAge:(q)arg0 ,

- (class)class,

- (void)dealloc,

- (BOOL)_isKVOA

)

KVO[23897:840022] 监听后Person ---NSKVONotifying_Person

(lldb) po [object_getClass(self.person1) instanceMethods]

<__NSArrayI0x60000022a560>(

- (void)setAge:(q)arg0 ,

- (q)age

)

(lldb) po [object_getClass(self.person2) instanceMethods]

<__NSArrayI0x6040002217a0>(

- (void)setAge:(q)arg0 ,

- (q)age

)

结论

  • RuntimeAPI动态生成一个NSKVONotifying_Person,并且让instance对象的isa指向这个全新的NSKVONotifying_Person
  • -setAge: 修改age会调用Foundation的_NSSetXXXValueAndNotify函数(下面有打印)
  • _NSSetXXXValueAndNotify函数会调用①willChangeValueForKey:,②然后调用原来的setter方法,③最后调用didChangeValueForKey:,在内部触发监听方法( observeValueForKeyPath:ofObject:change:context:)
  • 为了隐藏NSKVONotifying_Person子类,重写了class方法,返回Person(苹果真会搞事情)
  • -dealloc 清理现场
  • -_isKVO内部表示,判断这个类有没有动态生成子类

我们来证明一下

@implementationPerson

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

NSLog(@"%@",NSStringFromSelector(_cmd));

[superwillChangeValueForKey:key];

}

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

NSLog(@"begin---%@",NSStringFromSelector(_cmd));

[superdidChangeValueForKey:key];

NSLog(@"end---%@",NSStringFromSelector(_cmd));

}

@end
KVO[24586:884853] willChangeValueForKey:

KVO[24586:884853] begin---didChangeValueForKey:

KVO[24586:884853] {

kind =1;

new =20;

old =0;

}

KVO[24586:884853] end---didChangeValueForKey:



相关文章

  • Object-C中KVO探索

    什么是KVO KVO(Key-Value Observing),俗称键值监听。它提供一种机制,当指定的对象的属性被...

  • KVO&KVC

    什么是KVO? KVO是key-value observing的缩写 KVO是Object-C对观察者设计模式的又...

  • KVO/KVC

    什么是KVO KVO是Key-Value Observing的首字母缩写 KVO是Object-C对观察者设计模式...

  • GNUstep KVC/KVO探索(二):KVO的内部实现

    GNUstep KVC/KVO探索(一):KVC的内部实现GNUstep KVC/KVO探索(二):KVO的内部实...

  • GNUstep KVC/KVO探索(一):KVC的内部实现

    GNUstep KVC/KVO探索(一):KVC的内部实现GNUstep KVC/KVO探索(二):KVO的内部实...

  • KVO/KVC

    KVO是key-value observing的缩写kvo是object-c对观察者模式的又一实现apple使用了...

  • RxSwift(KVO底层探索)

    KVO底层探索请参考文章 KVO底层探索。 RxSwift对KVO的调用主要有两种方式: rx.observe()...

  • 探索中的KVO

    探索KVO的本质 什么是KVO KVO的全称就是Key-Value Observing ,俗称“键值监听”。用于监...

  • iOS底层--KVO(一)-基础知识点

    KVO: 全称--- Key-value observing 探索KVO原理和KVO一样,通过官方文档去看。 KV...

  • KVO探索

    概述 KVO(Key-Value Observing) 是苹果提供的一套事件通知机制。允许对象监听另一个对象特定属...

网友评论

    本文标题:Object-C中KVO探索

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