Runtime | 自定义KVO

准备工作

  1. 重写一个分类 一般是NSObject
  2. 需要导入一个头文件
#import 

头文件声明方法

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

方法实现

//self -->被观察者person
//observer -->观察者
- (void)rylsj_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 = [@"RYLSJKVO_" 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);
}

说明

  1. objc_registerClassPair 这个方法是重新注册了一个新类
  2. 参数使用的是char * 的 const char *newName = [newClassName UTF8String]; 这样可以把OC的字符串转换为char * 类型的

方法实现

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);
    //NSLog(@"修改完毕!");
    //拿到观察者
    id objc = objc_getAssociatedObject(self, @"objc");
    //通知观察者
    objc_msgSend(objc, @selector(observeValueForKeyPath:ofObject:change:context:),self,@"name",nil,nil);
    //改回子类类型
    object_setClass(self, class); 
}

说明

  1. 这里是C语言方法
  2. 这里修改了指针为自定义的对象
  3. 需要在setting中 搜索msg把YES设置为NO
设置msg为NO

你可能感兴趣的:(Runtime | 自定义KVO)