1.自定义观察者方法
- (void)lz_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
NSString *oldName = NSStringFromClass(self.class);
NSString *newName = [NSString stringWithFormat:@"LZKVO_%@",oldName];
//创建类
Class customClass = objc_allocateClassPair(self.class, newName.UTF8String, 0);
//注册类
objc_registerClassPair(customClass);
//修改指针
object_setClass(self, customClass);
//重写set方法
NSString *methodName = [NSString stringWithFormat:@"set%@:",keyPath.capitalizedString];
SEL sel = NSSelectorFromString(methodName);
class_addMethod(customClass, sel, (IMP)customSetMethod, "v@:@");
//保存观察者
objc_setAssociatedObject(self, (__bridge const void*)@"observer", observer, OBJC_ASSOCIATION_ASSIGN);
}
2.重写set方法并通知观察者
void customSetMethod(id self, SEL _cmd, NSString *name) {
//调用父类
struct objc_super superClass = {
self,
class_getSuperclass([self class])
};
objc_msgSendSuper(&superClass, _cmd, name);
id observer = objc_getAssociatedObject(self, (__bridge const void*)@"observer");
//发出通知
NSString *methodName = NSStringFromSelector(_cmd);
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];
objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:), key, self, @{key:name}, nil);
}
网友评论