美文网首页
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