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];

}

猜你喜欢

转载自www.cnblogs.com/StevenHuSir/p/Runtime_CustomKVO.html