涉及内容:

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. May Challenge 2017

    Chef and his daily routine 分析:水题,设置优先级,判断如果后面小于前面就输出no #include "iostream" #include " ...

  2. 最浅谈的SG函数

    [更新] Nim游戏的经验: 每次最多取m个——%(m+1) 阶梯nim——奇数位无视,看偶数位互相独立,成一堆一堆的石子 . . . . 既然被征召去汇总算法..那么挑个简单点的SG函数好了.. 介 ...

  3. javascript之常遇到的浏览器兼容问题和解决方法

    转自http://www.cnblogs.com/duenyang/p/6066737.html 常遇到的关于浏览器的宽高问题: var winW=document.body.clientWidth| ...

  4. 6-13 Hog特征1

    Hog特征与Haar特征有点不同,Hog特征是直接经过模板计算得到的

  5. hadoop推荐

    hadoop官网 我以Hadoop 2.7.3为例. hadoop 2.7.3 官网  . 用的操作系统是64bit Ubuntu14.04. 其中我们还可以学习 Apache Maven Proje ...

  6. poj 1186 方程的解数【折半dfs+hash】

    折半搜索,map会T所以用hash表来存状态 #include<iostream> #include<cstdio> #include<map> using nam ...

  7. 《编译原理》-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法

    <编译原理>-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法 此编译原理确定某高级程序设计语言编译原理,理论基础,学习笔记 本笔记是对教材< ...

  8. 【HDU - 1257】最少拦截系统(贪心)

    最少拦截系统 Descriptions: 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的 ...

  9. offsetLeft 与 left的区别

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 使用statement接口实现增,删,改操作