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