美文网首页
iOS- KVO的底层实现/响应式编程

iOS- KVO的底层实现/响应式编程

作者: Simple_Code | 来源:发表于2017-09-03 12:00 被阅读32次

    KVO 是 Objective-C 对观察者设计模式的一种实现

    KVO基本原理

    当观察某对象 A 时,KVO 机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性 keyPath 的 setter 方法。setter 方法随后负责通知观察对象属性的改变状况。

    KVO底层实现原理

    1.动态创建NSKVONotifying_Person,NSKVONotifying_Person是Person子类,做KVO
    2.修改当前对象的isa指针->NSKVONotifying_Person
    3.只要调用对象的set,就会调用NSKVONotifying_Person的set方法
    4.重写NSKVONotifying_Person的set方法,1.[super set:] 2.通知观察者,告诉你属性改变

    下面我们来实现KVO和自定义KVO

    Person类

    #import <Foundation/Foundation.h>
    @interface Person : NSObject
    @property (nonatomic, assign) int age;
    @end
    
    #import "Person.h"
    @implementation Person
    @end
    

    派生类

    #import "Person.h"
    @interface LPKVONotifying_Person : Person
    @end
    
    #import "LPKVONotifying_Person.h"
    #import <objc/runtime.h>
    @implementation LPKVONotifying_Person
    - (void)setAge:(int)age
    {
        [super setAge:age];
        // 通知观察者,属性改变
        id observer = objc_getAssociatedObject(self, @"observer");
        [observer observeValueForKeyPath:@"age" ofObject:self change:nil context:nil];
    }
    @end
    

    添加KVO分类

    #import <Foundation/Foundation.h>
    @interface NSObject (KVO)
    - (void)lp_addObserver:(NSObject *_Nullable)observer forKeyPath:(NSString *_Nullable)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
    @end
    
    #import "NSObject+KVO.h"
    #import <objc/runtime.h>
    #import "LPKVONotifying_Person.h"
    
    @implementation NSObject (KVO)
    - (void)lp_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
    {
        // 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,本质就是改变当前对象的类名
        object_setClass(self, [LPKVONotifying_Person class]);
        // 把观察者保存到当前对象里
        // 添加关联
        // id object:给哪个对象添加关联属性
        // key:属性名
        // value:关联值
        objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    @end
    

    调用

    #import "KVOViewController.h"
    #import "Person.h"
    #import "LPKVONotifying_Person.h"
    @interface KVOViewController ()
    @property (nonatomic, strong) Person *p;
    @end
    
    @implementation KVOViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // KVO
        //[self NSKVO];
        
        // 仿写KVO
        [self LPKVO];
    }
    - (void)NSKVO
    {
        Person *person = [[Person alloc]init];
        _p = person;
        [person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
    }
    - (void)LPKVO
    {
        Person *person = [[Person alloc]init];
        _p = person;
        [person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
        // 只要p的age属性一改变,就会调用观察者的observeValueForKeyPath
        
        // KVO底层实现:
        // 1.动态创建NSKVONotifying_Person,NSKVONotifying_Person是Person子类,做KVO
        // 2.修改当前对象的isa指针->NSKVONotifying_Person
        // 3.只要调用对象的set,就会调用NSKVONotifying_Person的set方法
        // 4.重写NSKVONotifying_Person的set方法,1.[super set:] 2.通知观察者,告诉你属性改变
        
        // 就是去判断有没有调用一个对象的set方法
    
    }
    // 监听的属性只要一改变就调用
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        NSLog(@"%d",_p.age);
    
    }
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        _p.age++;
        //    _p->_age ++;
    }
    
    

    相关文章

      网友评论

          本文标题:iOS- KVO的底层实现/响应式编程

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