kvo底层是用runtime实现的,核心原理一共有四步。
1. 根据已有类获取kvo子类类名:
NSString *kvoClassName = [NSString stringWithFormat:@"CBKVO_%@",NSStringFromClass([self class])];
Method setMethod = class_getInstanceMethod([self class], NSSelectorFromString(setName(keyPath)));
NSString *setName(NSString *keyPath) {
NSString *setName = [NSString stringWithFormat:@"set%@%@:",[[keyPath substringToIndex:1] uppercaseString],[keyPath substringFromIndex:1]];
return setName;
}
2. 根据类名,创建子类,添加自定义的set方法:
///2.1创建类
Class kvoClass = objc_allocateClassPair([self class], kvoClassName.UTF8String, 0);
//2.2添加方法
class_addMethod(kvoClass, NSSelectorFromString(setName(keyPath)), (IMP)KVO_SetMethod, method_getTypeEncoding(setMethod));
//2.3注册新类
objc_registerClassPair(kvoClass);
3. 交换两个类的指针:
object_setClass(self, kvoClass);
4. 在自定义的set函数中调用父类的set方法,改变属性值:
void KVO_SetMethod(id self ,SEL _cmd ,id value) {
NSLog(@"set方法执行了%@--%@",self,NSStringFromSelector(_cmd));
struct objc_super superClass = {
.receiver = self,
.super_class = class_getSuperclass([self class]),
};
void (*cbkvo_super)(void *,SEL,id) = (void *)objc_msgSendSuper;
cbkvo_super(&superClass,_cmd,value);
}