一丶原理
1.系統(tǒng)會(huì)為你監(jiān)聽的XXX類,創(chuàng)建一個(gè)NSKVONotifying_XXX子類;
2.為你監(jiān)聽的屬性,創(chuàng)建set方法;
3.set方法里,觸發(fā)observeValueForKeyPath方法;
4.注意的是,XXX的isa指針會(huì)指向NSKVONotifying_XXX;
二丶實(shí)現(xiàn)
需要關(guān)閉objc_msgsend檢查;
- (void)ZB_addObserver:(NSObject *_Nullable)observer forKeyPath:(NSString *_Nullable)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context{
//創(chuàng)建子類
NSString *oldClassName = NSStringFromClass([self class]);
NSString *newName = [@"ZB_" stringByAppendingString:oldClassName];
const char *newClassName = [newName UTF8String];
Class myClass = objc_allocateClassPair([self class], newClassName, 0);
//添加方法(俗稱重寫方法,其實(shí)子類本身沒有方法);
class_addMethod(myClass, @selector(setName:), (IMP)setName, "v@:@");
objc_registerClassPair(myClass);
//修改isa指針
object_setClass(self, myClass);
objc_setAssociatedObject(self, (__bridge const void *)@"zb", observer, OBJC_ASSOCIATION_RETAIN);
}
void setName(id self,SEL _cmd,NSString *newName){
id class = [self class];
object_setClass(self, class_getSuperclass([self class]));
//修改原來的值
objc_msgSend(self,@selector(setName:),newName);
id observer = objc_getAssociatedObject(self, (__bridge const void *)@"zb");
//通知
objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:),self,@"name",@{@"name":newName},nil);
object_setClass(self, class);
}
三丶代碼
https://github.com/k373379320/ZBKVO
iOS_技巧(10)KVO手動(dòng)發(fā)送通知
http://www.reibang.com/p/3f4203868d10