KVO的使用三:基于runtime实现KVO

         苹果的KVO原理通过isa-swizzling技术实现,本质实现逻辑是在runtime时添加一个子类,重写set方法进行操作,现在我们也基于runtime来实现一个KVO。

       首先新建一个Person类,继承自NSObject,添加一个name属性。

       然后给NSObject添加一个分类KVO,在分类中实现KVO的注册方法EZ_addObserver:forKeyPath: options:context:,这个方法的作用和系统的注册方法一样。先为Person动态添加一个子类EZKVO_Person,然后为其添加一个setName方法,因为我们要监听的是那么的变化。

- (void)EZ_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
    // 动态添加一个类
    NSString *className = [@"EZKVO_" stringByAppendingString:NSStringFromClass([self class])];
    const char *utfName = [className UTF8String];
    Class myClass = objc_allocateClassPair([self class], utfName, 0);
    
    // 添加setter方法
    class_addMethod(myClass, @selector(setName:), (IMP)setName, "v@:i");
    
    // 注册新添加的这个类
    objc_registerClassPair(myClass);
    
    // 修改被观察者的isa指针,isa指针指向Person类改为指向myclass类
    object_setClass(self, myClass);
    
    // 将观察者的属性保存到当前类里面去
    objc_setAssociatedObject(self, (__bridge const void *)@"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

       上面的是注册方法,下面处理的是在更改name属性值的时候,通过重写的set方法,将消息发出给观察者让其收到键值变化。过程是先取出被观察者,然后发送消息(即observeValueForKeyPath:ofObject:change:context:)让观察者接收。当然,也可以逻辑严谨些像系统那样向父类逐层调用,这里就不写出来了。

 

void setName(id self, SEL _cmd, id name) {
    // 取出观察者
    id objc = objc_getAssociatedObject(self, (__bridge const void *)@"objc");
 
    // 通知观察者
    ((void(*)(id,SEL,id,id,id,id))objc_msgSend)(objc, @selector(observeValueForKeyPath:ofObject:change:context:), name, self, nil, nil);
}

 

       最后沿用前面两篇文章的方法,在VC里添加触摸事件改变name的值,并在消息接收方法里打印信息(方便测试,就用了keyPath来代替change保存键值)。

 

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.person.name = @"小明";
}

 

      消息接收

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"name属性的改变为%@",keyPath);
}

     结果:2018-07-22 23:29:49.085057+0800 KVODemo[4402:212515] name属性的改变为小明

 

 

猜你喜欢

转载自www.cnblogs.com/xuanyishare/p/9352169.html
KVO