涉及内容:

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相关问题,可以看看博客前面的文章.

简洁的KVO -- 使用Block响应事件的更多相关文章

  1. 「iOS造轮子」之UIButton 用Block响应事件

    俗语说 一个不懒的程序员不是好程序员 造轮子,也只是为了以后更好的coding. coding,简易明了的代码更是所有程序员都希望看到的 无论是看自己的代码,还是接手别人的代码 都希望一看都知道这代码 ...

  2. 用block响应button的点击事件

    1.继承UIButton : 2.在自己定义的button类中的方法 addTarget:(id)target action:(SEL)action forControlEvents:(UIContr ...

  3. 用block做事件回调来简化代码,提高开发效率

       我们在自定义view的时候,通常要考虑view的封装复用,所以如何把view的事件回调给Controller就是个需要好好考虑的问题, 一般来说,可选的方式主要有target-action和de ...

  4. iOS 之单例,代理,通知,KVO,Block全能解析

    //单例 //.h + (Instannce *)shareInstance; //.m static Instannce *instance = nil; @implementation Insta ...

  5. UIView独占响应事件

    exclusiveTouch A Boolean value that indicates whether the receiver handles touch events exclusively. ...

  6. 让超出父视图范围的子视图响应事件,在UIView范围外响应点击

    /** *  在父视图中重写该方法,这样可使超出部分响应事件. */ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {  ...

  7. 解决UIButton 连续点击重复响应事件问题

    经常会遇到重复点击某个按钮 事件被响应多次的情景, 有时候可能对程序本身并没有什么影响 , 可有时候偏偏需要限制button响应事件直接的间隔 . 方法一 : 标记 1 . 利用空闲enable属性来 ...

  8. CSS鼠标响应事件经过、移动、点击示例介绍

    本文为大家介绍下CSS 鼠标响应事件:鼠标经过CSS.鼠标移动CSS.鼠标点击CSS以及示例,喜欢的朋友可以参考下   几种鼠标触发CSS事件. 说明: onMouseDown 按下鼠标时触发 onM ...

  9. android通知栏Notification点击,取消,清除响应事件

    主要是检测android通知栏的三种状态的响应事件 这次在实现推送需求的时候,要用到android通知栏Notification点击后进入消息页面,因为要实现一个保存推送用户名字的功能,我在点击后处理 ...

随机推荐

  1. JQ的双向数据绑定

    把渲染页面封装在function里面 在修改后直接调用,但是如果有alert();一定要注意function的摆放位置,正常应该是在alert前面,应为如果在后面会影响重新渲染的效果

  2. bzoj1222

    奇怪的dp 思路清奇 dp[i][j]表示当前做完了i个任务,1机器花了j秒,2机器花费的最少时间,然后转移就行了. #include<bits/stdc++.h> using names ...

  3. HDU 5884 Sort (二分+k叉哈夫曼树)

    题意:n 个有序序列的归并排序.每次可以选择不超过 k 个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T, 问 k最小是多少. 析:首先二分一下这个 k .然后在给定 k 的情况下, ...

  4. C++ STL自学总结,仅供参考

    本文内容,为博主在网上看到资料总结整合而来 一.stl格式简介 .stl文件是在计算机图形应用系统,来表示封闭的面或者体,用来表示三角形网格的一种文件格式.为STereo Lithography的缩写 ...

  5. E20180403-hm

    accompany vt. 陪伴,陪同; 附加,补充; 与…共存; 为…伴奏 synchronous adj. 同时存在[发生]的,同步的 asynchronous adj. 异步的; particu ...

  6. 【CodeForces - 501B 】Misha and Changing Handles(map)

    Misha and Changing Handles CodeForces原题是英文,这里就直接上中文好了,翻译不是太给力,但是不影响做题 ^▽^ Description  神秘的三角洲里还有一个传说 ...

  7. spark 机器学习 朴素贝叶斯 原理(一)

    朴素贝叶斯算法仍然是流行的挖掘算法之一,该算法是有监督的学习算法,解决的是分类问题,如客户是否流失.是否值得投资.信用等级评定等多分类问题.该算法的优点在于简单易懂.学习效率高.在某些领域的分类问题中 ...

  8. Django学习:ORM

    Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...

  9. poj 2412 The Balance 【exgcd】By cellur925

    题目传送门 一遇到数学就卡住,我这是怎么肥4...(或许到图论会愉悦吧,逃) Description * 给出两种重量为的 A, B 的砝码,给出一种使用最少的砝码的方式,称出重量 C. 我们可以比较 ...

  10. size_t与size_type区别

    size()  标准库string里面有个函数size,用来返回字符串中的字符个数,具体用法如下: string st("The expense of spirit\n");cou ...