昨天开始学习runtime写下做个记录,利用runtime实现系统的KVO,首先我们先来看一下系统的实现,首先定义Persion类添加一个name的属性,在ViewController类中初始化并添加一个kvo监听Persion类中name属性的变化
从控制台可以看出p对象的isa指向了一个NSKVONotifying_Persion的一个类.所以我们用runtime动态创建一个类重写其中的setName方法,在setName的方法中得到改变的值通过objc_msgSend()方法发送到viewController控制器中。
*注 xcode 9 objc_msgSend()传递多个参数需要把Enable Strict Checking of objc_msgSend Calls 设置为NO
下面主要利用runtime实现KVO主要代码实现
新建一个NSObject的Category
- (void)ZH_addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context{
//得到当前类名称
NSString*oldClassName =NSStringFromClass([selfclass]);
//自定义类名
NSString*NewClassName = [@"ZH_"stringByAppendingString:oldClassName];
//转换为c语言语法
constchar* newName = [NewClassNameUTF8String];
ClassMyclass =objc_allocateClassPair([selfclass], newName,0);
//重写setAge方法!!
class_addMethod(Myclass,@selector(setName:), (IMP)setName,"v@:@");
//注册这个类
objc_registerClassPair(Myclass);
//修改被观察者的isa指针!!让它指向自定义的类!!
object_setClass(self, Myclass);
//使用key绑定observer 以供下面发送通知使用
objc_setAssociatedObject(self,@"111", observer,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
void setName(idself,SEL_cmd,idname){
//保存当前类型
ClassfClass = [selfclass];
//改变当前对象指向父类!!
object_setClass(self,class_getSuperclass([selfclass]));
//调用父类的setName方法
objc_msgSend(self,@selector(setName:),name);
//拿出观察者
idobserver =objc_getAssociatedObject(self,@"111");
//通知外界
objc_msgSend(observer,@selector(observeValueForKeyPath:ofObject:change:context:),self,@"name",@{@"new":name},nil);
object_setClass(self, fClass);
}
利用业余时间记录一下,如有错误欢迎指正,有兴趣的朋友可以互相交流,希望大家共同进步。
网友评论