准备工作
- 重写一个分类 一般是NSObject
- 需要导入一个头文件
#import <objc/message.h>
头文件声明方法
- (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);
}
说明
- objc_registerClassPair 这个方法是重新注册了一个新类
- 参数使用的是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);
}
说明
- 这里是C语言方法
- 这里修改了指针为自定义的对象
- 需要在setting中 搜索msg把YES设置为NO