KVO

2017-12-25  本文已影响28人  6灰太狼9

理解

1.添加响应者,监听对象属性变化,当对象属性改变时调用代理。
2.动态创建NSKVONotifying_XX类,修改被监听对象isa指针指向,只要调用对象的set方法,就会调用NSKVONotifying_XX的set方法。本质:判断对象的set方法有没有被调用

监听一个Person类底层实现
1)、动态创建NSKVONotifying_Person,NSKVONotifying_Person是Person子类,做KVO;
2)、修改当前对象的isa指针->NSKVONotifying_Person;
3)、只要调用对象的set,就会调用NSKVONotifying_Person的set方法;
4)、重写NSKVONotifying_Person的set方法,1[super set:] 2、通知观察者,告诉属性改变。

每个对象都有 isa 指针,指向该对象的类,它告诉 Runtime 系统这个对象的类是什么。所以对象注册为被观察者时,isa 指针指向新子类,那么这个被观察的对象就神奇地变成新子类的对象了。在新类的set方法中会通知观察者。

为了测试kvo的实现方式,我们可以创建一个Person类,然后使用kvo监测name属性,然后在Person类中重写description方法。然后分别在添加kvo监控前后打印对象。

#import "Person.h"
#import <objc/runtime.h>
@implementation Person
-(NSString *)description{
    IMP nameIPM = [self methodForSelector:@selector(setName:)];
    NSLog(@"object address:%p\n  object setName: %p",self,nameIPM);

    Class objectMethodClass = [self class];
    Class objectRuntimeClass = object_getClass(self);
    Class superClass = class_getSuperclass(objectRuntimeClass);
    NSLog(@"objectMethodClass : %@, ObjectRuntimeClass : %@, superClass : %@ \n", objectMethodClass, objectRuntimeClass, superClass);
    return @"";
}

kvo中被观察者不会对观察者进行强引用。

nsnotification中从 iOS 9 开始通知中心会对观察者进行弱引用,所以不需要在观察者对象释放之前从通知中心移除。但是,通过-[NSNotificationCenter addObserverForName:object:queue:usingBlock]方法注册的观察者依然需要手动的释放,因为通知中心对它们持有的是强引用。

kvo缺陷

1.不支持block,代码分散。
2.在调用KVO时需要传入一个keyPath,由于keyPath是字符串的形式,所以其对应的属性发生改变后,字符串不易修改(因为不修改也不会有提示)。

推荐Facebook的一个KVO开源第三方框架-KVOControllerKVOController本质上是对系统KVO的封装,具有原生KVO所有的功能,而且规避了原生KVO的很多问题,兼容blockaction两种回调方式。

上一篇 下一篇

猜你喜欢

热点阅读