zoukankan      html  css  js  c++  java
  • Runtime(运行时)004-自定义KVO

    监听属性参数的变化

    @interface NSObject (HKKVO)

    - (void)HK_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;

    @end

    objc_allocateClassPair :创建一个类:

    objc_registerClassPair:注册一个类:

    class_addMethod :动态修改方法

    object_setClass :修改isa指针

    objc_setAssociatedObject : 保留观察者对象

    objc_getAssociatedObject :拿到观察者对象

     

    //self -->被观察者person

    //observer -->观察者

    - (void)HK_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context

    {

        /*

         1、自定义一个子类

         2、重写setName方法,在方法中,调用super的通知观察者

         3、修改当前的isa指针,指向自定义的子类

         */

        //1.动态生成一个类

        //1.1获取类名

        NSString *oldClassName = NSStringFromClass([self class]);

        NSString *newClassName = [@"HKKVO_" stringByAppendingString:oldClassName];

        const char *newName = [newClassName UTF8String];

        //创建一个类的class

        Class myClass = objc_allocateClassPair([self class], newName, 0);

        //注册类

        objc_registerClassPair(myClass);

        //2.添加set方法

        class_addMethod(myClass, @selector(setName:), (IMP)setName, "v@:@");

        //3.修改isa指针

        object_setClass(self, myClass);

        //4.保存观察者对象

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

        

    }

    void setName(id self,SEL _cmd,NSString *newName){

    //    NSLog(@"调用了setName方法!");

        //保存子类型

        id class = [self class];

     

        //改变self的isa指针

        object_setClass(self, class_getSuperclass(class));

     

        //调用父类的set方法

        objc_msgSend(self, @selector(setName:),newName);

     

        //拿到观察者

        id objc = objc_getAssociatedObject(self, @"objc");

     

        //通知观察者

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

     

        //改回子类类型

        object_setClass(self, class);

     

    }

    使用

       _p = [[Person alloc]init];

       [_p HK_addObserver:self forKeyPath:@"name" options:0 context:nil];

       NSLog(@"%@",[_p class]);

    //监听name修改状态

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context

    {

        NSLog(@"name 被修改为:%@",_p.name);

    }

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

        static int i = 0;

        i++;

        _p.name = [NSString stringWithFormat:@"CC_%d",i];

    }

  • 相关阅读:
    Docker
    Dotted lines by default in ViVA
    8245H(C2)光猫配置方法
    两种将verilog网表转为spice网表的方法
    calibredrv create reference cell
    怎么flatten一个GDS所有层次
    路由器后面访问光猫
    贝尔IPTV
    PDK导出的cdl MOS四端顺序不正确
    如何删除已经存在lib的techfile
  • 原文地址:https://www.cnblogs.com/StevenHuSir/p/Runtime_CustomKVO.html
Copyright © 2011-2022 走看看