美文网首页
iOS 自定义KVO

iOS 自定义KVO

作者: 出来遛狗了 | 来源:发表于2020-03-04 17:00 被阅读0次

上一篇讲到了KVO的底层实现原理,这一篇说一下怎么去自定义KVO
首先创建一个NSObject的category,自己写一个addobserver方法


image.png

1.获取当前类名,为新创建的类添加名字


image.png
2.使用runtime添加类(参数:父类, 类名)
image.png
3.注册类
image.png

4.动态修改self的类型


image.png
5.重写set方法->给子类对象添加set方法
image.png
6.重写set方法,并给父类发送set方法给属性赋值
image.png

7.为当前类绑定一个observer属性,方便在setName中获取
8.为当前类绑定一个keyPath,方便在setName中获取


image.png

9.在setCustomMethod中获取observer,发送observeValueForKeyPath方法


image.png

自定义完成
接下来看运行结果


image.png
/*********************完整代码****************/
NSObject+KVO.h中
@interface NSObject (KVO)
- (void)RH_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
@end

NSObject+KVO.m中

#import "NSObject+KVO.h"

#import <objc/message.h>
@implementation NSObject (KVO)
-(void)RH_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
    // 1.获取当前类的名字
    NSString *oldClassName = NSStringFromClass([self class]);
    NSString *newClassName  = [@"RHNotifying_" stringByAppendingString: oldClassName];
    //2.使用runtime添加类(参数:父类, 类名)
    Class myClass = objc_allocateClassPair([self class], newClassName.UTF8String, 0);
    //3.注册类
    objc_registerClassPair(myClass);
    //4.动态修改self的类型
    object_setClass(self, myClass);
    
    //5.重写set方法->给子类对象添加set方法
        //获取方法名
    NSString *methodName = [@"set" stringByAppendingString:keyPath.capitalizedString];
    methodName = [methodName stringByAppendingString:@":"]; //因为有参数,所以方法名要加:
    SEL setMethod = NSSelectorFromString(methodName);

    class_addMethod(myClass, setMethod, (IMP)setCustomMethod, "v@:@");
    //6.为当前类绑定一个observer属性,方便在setName中获取
    objc_setAssociatedObject(self, (__bridge const void *)@"oberver", observer, OBJC_ASSOCIATION_ASSIGN);
    //7.为当前类绑定一个keyPath,方便在setName中获取
    objc_setAssociatedObject(self, (__bridge const void *)@"keyPath", keyPath, OBJC_ASSOCIATION_ASSIGN);
}
void setCustomMethod(id self, SEL _cmd, NSString *new){
    //调用父类的set方法给name赋值
    struct objc_super person = {
        self,
        class_getSuperclass([self class])
    };
    // 修改父类的属性
    objc_msgSendSuper(&person, _cmd, new);
    
    //获取observer,发送observeValueForKeyPath方法
    id observer = objc_getAssociatedObject(self, @"oberver");
    id keyPath = objc_getAssociatedObject(self, @"keyPath");
    objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:),keyPath,self, @{keyPath: new}, nil);
    
}
@end

demo代码

相关文章

网友评论

      本文标题:iOS 自定义KVO

      本文链接:https://www.haomeiwen.com/subject/tdmvlhtx.html