利用Runtime 实现简单的自定义kvo
代码github github.com/zswj/custom-KVO
系统kvo实现原理:主要原理是:创建个被监听对象的子类,然后重新被监听属性的set方法,当这个属性被修改的时候,就让监听者调用某个方法
实现:创建个继承与NSObject的Person 并添加个age属性
为NSObject添加个分类 并添加一个监听方法
- (void)ZS_addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context;
添加kvo监听
Person*p = [[Personalloc]init];
p.age=18;
_p= p;
//自定义KVO
[pZS_addObserver:selfforKeyPath:@"age"options:NSKeyValueObservingOptionNewcontext:nil];
NSObject分类中实现
这个方法
- (void)ZS_addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context {
//动态建个子类!重写监听属性的set方法
/*
1.自定义一个类继承与self
2.重写父类的被监听的属性的set方法(age)
3.调用obsetver的observeValueForKeyPath方法
*/
//动态添加一个类
NSString* oldClassN =NSStringFromClass([selfclass]);
NSString* newClassN = [@"zs_"stringByAppendingString:oldClassN];
constchar*name = [newClassNUTF8String];
//创建Person的子类
Class MyClass =objc_allocateClassPair([selfclass], name,0);
//重写setAge方法
class_addMethod(MyClass,@selector(setAge:), (IMP)setAge,"v@:i");
//注册一个类(注册这个子类)
objc_registerClassPair(MyClass);
//修改被观察对象的isa指针也就是self的isa指针此刻self就是继承与Person的子类对象
object_setClass(self, MyClass);
//将观察者属性保存到当前累里面(被监听的值改变的时候,可取出执行方法)
objc_setAssociatedObject(self, (__bridgeconstvoid*)@"objc", observer,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//相当于重写setAge方法实现
voidsetAge(idself,SEL_cmd,intage) {
/*
要调用super的setAge方法
让这个类指针指向父类调用setAge方法后在让这个类指向子类
*/
//保存当前类
Class myClass = [selfclass];
NSLog(@"调用了没有%@",self);
//将self的isa指针改成父类调用父类的setAge方法
object_setClass(self,class_getSuperclass([selfclass]));
//调用父类
objc_msgSend(self,@selector(setAge:), age);
//通知观察者
//拿出观察者
idobjc =objc_getAssociatedObject(self, (__bridgeconstvoid*)@"objc");
//通知观察者执行方法
objc_msgSend(objc,@selector(observeValueForKeyPath:ofObject:change:context:),self,@"age",nil,nil);
//再把当前类改成子类
object_setClass(self, myClass);
}