要实现will/didChangeValueForKey:方法javascript
kvo的实例 实际在运行时被调用java
- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;复制代码
触发数组
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context;复制代码
所以要实现KVO,须要下列条件之一便可post
依赖于Runtimeui
动态建立被观察对象的子类,重写setter方法,而且要管理一个对象的全部观察者.spa
// 子类名
NSString *kvoclassName = [kXJYKVOPrefix stringByAppendingString:originalclassName];
Class class = NSClassFromString(kvoclassName);
if (class) {
return class;
}
// class doesn't exist yet, make it
Class originalclass = object_getClass(self);
Class kvoclass = objc_allocateClassPair(originalclass, kvoclassName.UTF8String, 0);
// 得到签名
Method classMethod = class_getInstanceMethod(originalclass, @selector(class));
const char *types = method_getTypeEncoding(classMethod);
// 替换setter 实现
class_addMethod(kvoClazz, @selector(class), (IMP)kvo_class, types);
objc_registerClassPair(kvoclass);
return kvoclass;复制代码
改变isa指针
isa指针的做用: isa指针指向实例的类(对于这里的状况)
实例经过isa指针找到类,能够获得方法列表,属性列表等信息
当咱们将isa指针指向子类时,就能够调用子类的方法,使用子类的属性等。
因而,调用该实例的setter方法实际上是调用了子类的setter方法。指针
管理观察者
因为一个对象可能被多个观察者观察,因此能够用关联对象的方法来管理全部的观察者。code
XJYObservationInfo *info = [[XJYObservationInfo alloc]initWithObserver:self key:key block:block];
// 维护改KVO观察者数组
NSMutableArray *observers = objc_getAssociatedObject(self, (__bridge const void *)(kXJYKVOAssociatedObservers));
if (!observers) {
observers = [NSMutableArray array];
objc_setAssociatedObject(self, (__bridge const void *)(kXJYKVOAssociatedObservers), observers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
[observers addObject:info];复制代码
重写class方法server
class_addMethod(kvoClazz, @selector(class), (IMP)kvo_class, types);
static Class kvo_class(id self, SEL _cmd)
{
return class_getSuperclass(object_getClass(self));
}复制代码
还记得Aspects中 对于KVO的特殊处理吗,KVO改变了实例对象的isa指针,在此处 Aspects对KVO过的实例进行了特殊的处理
Aspects:对象
// Probably a KVO'ed class. Swizzle in place. Also swizzle meta classes in place.
else if (statedClass != baseClass) {
return aspect_swizzleClassInPlace(baseClass);
}复制代码
object.class 因为KVO重写了class方法,因此不能准确的找到类 object_getClass()方法能够准确的找到isa指针 object.class 与 object_getClass(object)进行判断 来防止KVO致使的AOP无效复制代码
「掘金技术征文」
juejin.im/post/58d8e9…