简洁的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相关问题,可以看看博客前面的文章.
简洁的KVO -- 使用Block响应事件的更多相关文章
- 「iOS造轮子」之UIButton 用Block响应事件
俗语说 一个不懒的程序员不是好程序员 造轮子,也只是为了以后更好的coding. coding,简易明了的代码更是所有程序员都希望看到的 无论是看自己的代码,还是接手别人的代码 都希望一看都知道这代码 ...
- 用block响应button的点击事件
1.继承UIButton : 2.在自己定义的button类中的方法 addTarget:(id)target action:(SEL)action forControlEvents:(UIContr ...
- 用block做事件回调来简化代码,提高开发效率
我们在自定义view的时候,通常要考虑view的封装复用,所以如何把view的事件回调给Controller就是个需要好好考虑的问题, 一般来说,可选的方式主要有target-action和de ...
- iOS 之单例,代理,通知,KVO,Block全能解析
//单例 //.h + (Instannce *)shareInstance; //.m static Instannce *instance = nil; @implementation Insta ...
- UIView独占响应事件
exclusiveTouch A Boolean value that indicates whether the receiver handles touch events exclusively. ...
- 让超出父视图范围的子视图响应事件,在UIView范围外响应点击
/** * 在父视图中重写该方法,这样可使超出部分响应事件. */ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { ...
- 解决UIButton 连续点击重复响应事件问题
经常会遇到重复点击某个按钮 事件被响应多次的情景, 有时候可能对程序本身并没有什么影响 , 可有时候偏偏需要限制button响应事件直接的间隔 . 方法一 : 标记 1 . 利用空闲enable属性来 ...
- CSS鼠标响应事件经过、移动、点击示例介绍
本文为大家介绍下CSS 鼠标响应事件:鼠标经过CSS.鼠标移动CSS.鼠标点击CSS以及示例,喜欢的朋友可以参考下 几种鼠标触发CSS事件. 说明: onMouseDown 按下鼠标时触发 onM ...
- android通知栏Notification点击,取消,清除响应事件
主要是检测android通知栏的三种状态的响应事件 这次在实现推送需求的时候,要用到android通知栏Notification点击后进入消息页面,因为要实现一个保存推送用户名字的功能,我在点击后处理 ...
随机推荐
- The Castle
链接 分析:先暴力求出联通块数和最大联通块包含多少,接着对于每个位置判断去掉其上下左右的四个位置的墙之后的最大联通块数,并且记得先选最西,然后选最南的顺序了来输出 /* PROB:castle ID: ...
- 【BZOJ 3884】 上帝与集合的正确用法
[题目链接] 点击打开链接 [算法] 通过欧拉拓展定理,列出递推公式 [代码] #include<bits/stdc++.h> using namespace std; typedef l ...
- wsdl 生成代码 WCF
具体方法: 打开Microsoft Visual Studio 2008->Visual Studio Tools->Visual Studio 2008 命令提示窗口. 输入:wsdl ...
- nodejs URL 详解
1 我们可以使用.parse方法来将一个URL字符串转换为URL对象 例如: url.parse('http://user:pass@host.com:8080/p/a/t/h?query=strin ...
- lnmp-详细编译安装步骤
CentOS 7.0编译安装Nginx1.6.0+MySQL5.6.19+PHP5.5.14 一.配置防火墙,开启80端口.3306端口 CentOS 7.0默认使用的是firewall作为防火墙,这 ...
- VPS 安全措施(CentOS 6)
新到手一台VPS,要做的第一件事大概是做好安全措施. 下面针对CentOS 6随便写点,我目前做的几步是: 修改root密码 SSH-key登录 配置iptable 安装fail2ban 1.修改ro ...
- EasyUI 扩展自定义EasyUI校验规则 验证规则(常用的)
$.extend($.fn.validatebox.defaults.rules, { CHS: { validator: function (value, param) { return /^[\u ...
- 斯坦福CS231n—深度学习与计算机视觉----学习笔记 课时24&&25
课时24 深度学习开源库使用介绍(上) Caffe 被用于重新实现AlexNet,然后用AlexNet的特征来解决其他事情 用C++书写的,可以去GitHub上面读取源代码 主要四个类: Blob可以 ...
- 51nod 1276 【离线化】
思路1.: 离线处理: 具体就是把岛屿离线然后按照高度排序,把query按照从高到低排序,然后每次query只要从最高的岛屿开始找起,判断条件:如果他旁边都是没有被找过的(也就是默认是海),那么数量+ ...
- Codeforces626B - Cards【模拟】
题意: 两张相同可以合并成相同: 两张不同可以产生另外一个不同: 求最终的可能颜色: 思路: 模拟啊. 总共也就那么几种情况,具体看挫code--. #include<iostream> ...