美文网首页
iOS 自定义KVO

iOS 自定义KVO

作者: 我是数据链路层 | 来源:发表于2017-05-03 17:14 被阅读0次

    利用Runtime 实现简单的自定义kvo 

    代码github github.com/zswj/custom-KVO


    系统kvo实现原理:主要原理是:创建个被监听对象的子类,然后重新被监听属性的set方法,当这个属性被修改的时候,就让监听者调用某个方法

    实现:创建个继承与NSObject的Person 并添加个age属性

    为NSObject添加个分类 并添加一个监听方法

    - (void)ZS_addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context;

    添加kvo监听

    Person*p = [[Personalloc]init];

    p.age=18;

    _p= p;

    //自定义KVO

    [pZS_addObserver:selfforKeyPath:@"age"options:NSKeyValueObservingOptionNewcontext:nil];

    NSObject分类中实现

    这个方法 

    - (void)ZS_addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context {

    //动态建个子类!重写监听属性的set方法

    /*

    1.自定义一个类继承与self

    2.重写父类的被监听的属性的set方法(age)

    3.调用obsetver的observeValueForKeyPath方法

    */

    //动态添加一个类

    NSString* oldClassN =NSStringFromClass([selfclass]);

    NSString* newClassN = [@"zs_"stringByAppendingString:oldClassN];

    constchar*name = [newClassNUTF8String];

    //创建Person的子类

    Class MyClass =objc_allocateClassPair([selfclass], name,0);

    //重写setAge方法

    class_addMethod(MyClass,@selector(setAge:), (IMP)setAge,"v@:i");

    //注册一个类(注册这个子类)

    objc_registerClassPair(MyClass);

    //修改被观察对象的isa指针也就是self的isa指针此刻self就是继承与Person的子类对象

    object_setClass(self, MyClass);

    //将观察者属性保存到当前累里面(被监听的值改变的时候,可取出执行方法)

    objc_setAssociatedObject(self, (__bridgeconstvoid*)@"objc", observer,OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    }

    //相当于重写setAge方法实现

    voidsetAge(idself,SEL_cmd,intage) {

    /*

    要调用super的setAge方法

    让这个类指针指向父类调用setAge方法后在让这个类指向子类

    */

    //保存当前类

    Class myClass = [selfclass];

    NSLog(@"调用了没有%@",self);

    //将self的isa指针改成父类调用父类的setAge方法

    object_setClass(self,class_getSuperclass([selfclass]));

    //调用父类

    objc_msgSend(self,@selector(setAge:), age);

    //通知观察者

    //拿出观察者

    idobjc =objc_getAssociatedObject(self, (__bridgeconstvoid*)@"objc");

    //通知观察者执行方法

    objc_msgSend(objc,@selector(observeValueForKeyPath:ofObject:change:context:),self,@"age",nil,nil);

    //再把当前类改成子类

    object_setClass(self, myClass);

    }

    相关文章

      网友评论

          本文标题:iOS 自定义KVO

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