kvo底層是用runtime實(shí)現(xiàn)的蝗羊,核心原理一共有四步嫂易。
1. 根據(jù)已有類獲取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. 根據(jù)類名谭胚,創(chuàng)建子類哮翘,添加自定義的set方法:
///2.1創(chuàng)建類
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注冊(cè)新類
objc_registerClassPair(kvoClass);
3. 交換兩個(gè)類的指針:
object_setClass(self, kvoClass);
4. 在自定義的set函數(shù)中調(diào)用父類的set方法颈嚼,改變屬性值:
void KVO_SetMethod(id self ,SEL _cmd ,id value) {
NSLog(@"set方法執(zhí)行了%@--%@",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);
}