美文网首页程序员
好用的 KVO 转 Block 监听分类

好用的 KVO 转 Block 监听分类

作者: 莱姆船长 | 来源:发表于2018-05-11 17:30 被阅读0次

    .h 文件

    #import <Foundation/Foundation.h>
    
    typedef void (^LGFKVOBlock)(NSDictionary *change, void *context);
    
    @interface NSObject (LGFKVOBlocks)
    
    #pragma mark - 给某个 NSObject 注册KVO监听 使用block进行回调
    /**
     @param observer 监听对象
     @param keyPath 监听 属性 key 值
     @param options NSKeyValueObservingOptions
     @param context 附带内容
     @param block block回调
     */
    + (void)lgf_AddObserver:(NSObject *)observer
             forKeyPath:(NSString *)keyPath
                options:(NSKeyValueObservingOptions)options
                context:(void *)context
              withBlock:(LGFKVOBlock)block;
    
    #pragma mark - 删除某个 NSObject 的 KVO BLOCK 监听
    /**
     @param observer 监听对象
     @param keyPath 监听 属性 key 值
     */
    + (void)lgf_RemoveBlockObserver:(NSObject *)observer
                    forKeyPath:(NSString *)keyPath;
    
    #pragma mark - 给自己注册KVO监听 使用block进行回调
    /**
     @param keyPath 监听 属性 key 值
     @param options NSKeyValueObservingOptions
     @param context 附带内容
     @param block block回调
     */
    - (void)lgf_AddObserverForKeyPath:(NSString *)keyPath
                         options:(NSKeyValueObservingOptions)options
                         context:(void *)context
                       withBlock:(LGFKVOBlock)block;
    
    #pragma mark - 删除自己的 KVO BLOCK 监听
    /**
     @param keyPath 监听 属性 key 值
     */
    - (void)lgf_RemoveBlockObserverForKeyPath:(NSString *)keyPath;
    
    @end
    

    .m 文件

    #import "NSObject+LGFKVOBlocks.h"
    #import "LGFOCTool.h"
    
    @implementation NSObject (LGFKVOBlocks)
    
    #pragma mark - 给某个 NSObject 注册KVO监听 使用block进行回调
    /**
     @param observer 监听对象
     @param keyPath 监听 属性 key 值
     @param options NSKeyValueObservingOptions
     @param context 附带内容
     @param block block回调
     */
    + (void)lgf_AddObserver:(NSObject *)observer
            forKeyPath:(NSString *)keyPath
               options:(NSKeyValueObservingOptions)options
               context:(void *)context
             withBlock:(LGFKVOBlock)block {
        
        objc_setAssociatedObject(observer, (__bridge const void *)(keyPath), block, OBJC_ASSOCIATION_COPY);
        [self addObserver:observer forKeyPath:keyPath options:options context:context];
    }
    
    #pragma mark - 删除某个 NSObject 的 KVO BLOCK 监听
    /**
     @param observer 监听对象
     @param keyPath 监听 属性 key 值
     */
    + (void)lgf_RemoveBlockObserver:(NSObject *)observer
                    forKeyPath:(NSString *)keyPath {
        objc_setAssociatedObject(observer, (__bridge const void *)(keyPath), nil, OBJC_ASSOCIATION_COPY);
        [self removeObserver:observer forKeyPath:keyPath];
    }
    
    #pragma mark - 给自己注册KVO监听 使用block进行回调
    /**
     @param keyPath 监听 属性 key 值
     @param options NSKeyValueObservingOptions
     @param context 附带内容
     @param block block回调
     */
    - (void)lgf_AddObserverForKeyPath:(NSString *)keyPath
                         options:(NSKeyValueObservingOptions)options
                         context:(void *)context
                       withBlock:(LGFKVOBlock)block {
        objc_setAssociatedObject(self, (__bridge const void *)(keyPath), block, OBJC_ASSOCIATION_COPY);
        [self addObserver:self forKeyPath:keyPath options:options context:context];
    }
    
    #pragma mark - 删除自己的 KVO BLOCK 监听
    /**
     @param keyPath 监听 属性 key 值
     */
    - (void)lgf_RemoveBlockObserverForKeyPath:(NSString *)keyPath {
        objc_setAssociatedObject(self, (__bridge const void *)(keyPath), nil, OBJC_ASSOCIATION_COPY);
        [self removeObserver:self forKeyPath:keyPath];
    }
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Class class = [self class];
            SEL observeValueForKeyPath = @selector(observeValueForKeyPath:ofObject:change:context:);
            SEL lgf_ObserveValueForKeyPath = @selector(lgf_ObserveValueForKeyPath:ofObject:change:context:);
            [LGFAllMethod lgf_MethodReplaceWithClass:class selOne:observeValueForKeyPath selTwo:lgf_ObserveValueForKeyPath];
        });
    }
    
    - (void)lgf_ObserveValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary *)change
                           context:(void *)context {
        LGFKVOBlock block = objc_getAssociatedObject(self, (__bridge const void *)(keyPath));
        block(change, context);
    }
    
    @end
    

    分类中方法必须替换
    [LGFAllMethod lgf_MethodReplaceWithClass:class selOne:observeValueForKeyPath selTwo:lgf_ObserveValueForKeyPath];

    #pragma mark - 运行时方法替换
    /**
     @param class 方法所属的类
     @param selOne 被替换的方法
     @param selTwo 替换的方法
     */
    + (void)lgf_MethodReplaceWithClass:(Class)class selOne:(SEL)selOne selTwo:(SEL)selTwo {
        Method met_One = class_getInstanceMethod(class, selOne);
        Method met_Two = class_getInstanceMethod(class, selTwo);
        BOOL didAddMethod =
        class_addMethod(class, selOne, method_getImplementation(met_Two), method_getTypeEncoding(met_Two));
        if (didAddMethod) {
            class_replaceMethod(class, selTwo, method_getImplementation(met_One), method_getTypeEncoding(met_One));
        } else {
            method_exchangeImplementations(met_One, met_Two);
        }
    }
    

    以上 新建类复制黏贴即可

    相关文章

      网友评论

        本文标题:好用的 KVO 转 Block 监听分类

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