美文网首页程序员
好用的 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