1.KVO 使用
添加观察者 addObserver:forKeyPath:options:context
监听 observeValueForKeyPath:ofObject:change:context
移除观察者 removeObserver:forKeyPath removeObserver:forKeyPath:context
注:方法对应参数具体作用名称可参考官方文档不多赘述
2.KVO 触发模式
通过 + (BOOL) automaticallyNotifiesObserversForKey 返回值控制手动模式还是自动模式 默认为YES
3. KVO底层原理
1.创建一个子类
2.重写setter方法
3.设置isa指针
4.自定义KVO(通过runtime实现)
NSString *getValue(NSString *setter){
NSRange range = NSMakeRange(3, setter.length - 4);
NSString *key = [setter substringWithRange:range];
NSString *letter = [[key substringToIndex:1] lowercaseString];
key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:letter];
return key;
}
void setterMethodIMP(id self, SEL _cmd , NSString *newVaule){
//第一种方式 改变父类属性
struct objc_super superClass = {
self,
class_getSuperclass([self class])
};
//调用父类方法
objc_msgSendSuper(&superClass, _cmd, newVaule);
// 另一种 改变父类属性
Class class = [ self class]; //拿到当前对象
object_setClass(self,class_getSuperClass(class));
objc_msgSend(self, _cmd,newValue);
最后 通知观察者后改回子类
object_setClass(self,class);
//注:选其中一种即可
//获取观察者
id observer = objc_getAssociatedObject(self, (__bridge const void*)@"objc");
//通知发生改变
NSString *methodName = NSStringFromSelector(_cmd);
//setName
NSString *key = getValue(methodName);
if (observer) {
objc_msgSend(observer,@selector(observeValueForKeyPath:ofObject:change:context:),key,self,@{key:newVaule},nil);
}
}
- (void)king_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
// 注册类
NSString *oldName = NSStringFromClass([self class]);
NSString *newName = [NSString stringWithFormat:@"customKVO_%@",oldName];
Class customClass = objc_allocateClassPair([self class], newName.UTF8String, 0);
//设置isa 指针 指向
object_setClass(self, customClass);
//重写setName方法
NSString *methodName = [NSString stringWithFormat:@"set%@:",keyPath.capitalizedString];
SEL sel = NSSelectorFromString(methodName);
//参数
class 给哪个类添加方法
sel 方法名称
imp 方法实现(函数指针)
type 返回值类型
class_addMethod(customClass, sel, (IMP)setterMethodIMP, "v@:@");
//关联对象
objc_setAssociatedObject(self, (__bridge const void *)@"objc", observer, OBJC_ASSOCIATION_ASSIGN);
}