zoukankan      html  css  js  c++  java
  • 简洁的KVO -- 使用Block响应事件

    涉及内容:

    KVO,Runtime,Category,Block

    首先创建NSObject的Category

    举个例子是这样的:

    随后定义你需要响应的Block结构

    我简单一点就这样咯

    typedef void(^NickyObserverBlock)(id oldValue,id newValue);

    添加方法

    - (void)setObserveKeyPath:(id)keypath signal:(NSString *)sign didChangedBlock:(NickyObserverBlock)block;

    keypath就不解释了,singal是标识

    标识存在的意义是 在多个observe中 对同一个对象监听时 作为区分作用

    随后往NSObject里添加一个字典对象 用作存储 对象设置的block和keypath+signal

    字典的key为 keypath+signal object为block

    随后实现上面定义的setObserve方法

    - (void)setObserveKeyPath:(id)keypath signal:(NSString *)sign didChangedBlock:(NickyObserverBlock)block{
        [self.changeBlockMaps setObject:block forKey:[NSString stringWithFormat:@"%@%p",keypath,&sign]];
        [self addObserver:self forKeyPath:keypath options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:&sign];
    }

    在实现方法 里,对象给自己添加KVO,同时设置keypath及context,context必须设置,不然后面在kvo响应里无法取到我们字典里存储的block

    然后实现kvo事件:

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        NSString *path = [NSString stringWithFormat:@"%@%p",keyPath,context];
        NickyObserverBlock block = [self.changeBlockMaps objectForKey:path];
        if (block){
            block(change[@"old"],change[@"new"]);
        }
    }

    path为前面设置时拼接的keypath+signal

    取到里面的block对象,并执行

    到最后 请不要忘记对象销毁时手动把observe remove掉(虽然ios10之后不remove也不会崩...)..

    完整的category:

    .h

    #import <Foundation/Foundation.h>
    typedef void(^NickyObserverBlock)(id oldValue,id newValue);
    @interface NSObject (NickyKVO)
    - (void)setObserveKeyPath:(id)keypath didChangedBlock:(NickyObserverBlock)block;
    - (void)setObserveKeyPath:(id)keypath signal:(NSString *)sign didChangedBlock:(NickyObserverBlock)block;
    
    @end

    .m

    //
    //  NSObject+NickyKVO.m
    //  KvoDemo
    //
    //  Created by NickyTsui on 2018/3/30.
    //  Copyright © 2018年 nickytsui. All rights reserved.
    //
    
    #import "NSObject+NickyKVO.h"
    #import <objc/runtime.h>
    @interface NSObject()
    @property (strong,nonatomic) NSMutableDictionary <NSString *,NickyObserverBlock>                *changeBlockMaps;
    @end
    
    @implementation NSObject (NickyKVO)
    - (void)setObserveKeyPath:(id)keypath signal:(NSString *)sign didChangedBlock:(NickyObserverBlock)block{
        [self.changeBlockMaps setObject:block forKey:[NSString stringWithFormat:@"%@%p",keypath,&sign]];
        [self addObserver:self forKeyPath:keypath options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:&sign];
    }
    - (void)setObserveKeyPath:(id)keypath didChangedBlock:(NickyObserverBlock)block{
        [self setObserveKeyPath:keypath signal:@"" didChangedBlock:block];
    }
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        NSString *path = [NSString stringWithFormat:@"%@%p",keyPath,context];
        NickyObserverBlock block = [self.changeBlockMaps objectForKey:path];
        if (block){
            block(change[@"old"],change[@"new"]);
        }
    }
    
    - (NSMutableDictionary<NSString *,NickyObserverBlock> *)changeBlockMaps{
        NSMutableDictionary<NSString *,NickyObserverBlock> * maps = objc_getAssociatedObject(self,_cmd);
        if (!maps){
            maps = [[NSMutableDictionary alloc]init];
            self.changeBlockMaps = maps;
        }
        return maps;
    }
    - (void)setChangeBlockMaps:(NSMutableDictionary *)changeBlockMaps{
        objc_setAssociatedObject(self, @selector(changeBlockMaps), changeBlockMaps, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    }
    @end

    另外 这里涉及Category里创建一个property相关问题,可以看看博客前面的文章.

  • 相关阅读:
    500内部服务器错误
    silverlight中实现页面传值
    每个程序员必备的10种工具
    ora-12514:TNS:listener does not currently know of service requested in connect descriptor
    利用VBA 宏实现vc6.0的自动添加注释和自动取消注释
    plsql developer (在8.04版本中试过可用)
    修改Oracle数据库字符集
    80端口被占用(端口检查)解决
    sql server分页
    解决问题 “You don't have permission to access /index.html on this server.”
  • 原文地址:https://www.cnblogs.com/n1ckyxu/p/8805761.html
Copyright © 2011-2022 走看看