多delegate的使用

一般在我们使用delegate都知道,是一对一的关系。在目前的项目中,有这样一个需求,在服务端收到了一个下发事件,需要在不同的页面,不同的VC都收到此事件,并进行相应的处理。当然这个用RAC实现很简单,但是目前的项目是一个SDK,如果将ReactiveCocoa引入进来,工程会增大很多,这样明显是不合理的,这个时候,就想到了多代理这个思路。其实也是从之前写的proxy代理类的想法而来。

实现思路

主要是利用OC的runtime,将一个代理类作为中间类,当收到服务器下发的通知时,通过调用代理类的方法,在代理类中实现消息转发机制,将selector转发给各个代理类。

还是看代码。

首先,我们是将各个代理存在中间类中,这样才能转发到各个代理。

@interface PPSMutableDelegate : NSObject- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;- (void)removeDelegate:(id)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;- (void)removeDelegate:(id)delegate;- (void)removeAllDelegates;@end
复制代码

在需要监听的delegate中 通过addDelegate将代理添加进去就行,加入queue的目的是为了,在某些收到消息的方法中,需要进行一些异步处理。如果要在主线程中处理,直接放dispatch_get_main_queue()就ok

实现

//代理对象和代理队列持有类
@interface PPSDelegateNode : NSObject@property (nonatomic, weak) id delegate;
@property (nonatomic, strong) dispatch_queue_t delegateQueue;- (id)initWithDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;@end@implementation PPSDelegateNode- (id)initWithDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue {self = [super init];if (self) {_delegate = delegate;_delegateQueue = delegateQueue;}return self;
}@end复制代码

这就是一个model类,用来存储一下delegate

在具体的PPSMutableDelegate实现中,用了一个NSMutableArray用来储存delegate 在进行消息转发时,遍历数组 转发出去就行,实现也很简单

在实现消息转发时,主要是通过

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
复制代码

在实现methodSignatureForSelector:方法时,要注意在这个方法中不能返回nil 否则会崩溃的,所以如果delegate中没有找到实现,可以在当前实现一个空的方法

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {for (PPSDelegateNode *node in self.delegateNodes) {id nodeDelegate = node.delegate;NSMethodSignature *result = [nodeDelegate methodSignatureForSelector:aSelector];if (result != nil) {return result;}}return [[self class] instanceMethodSignatureForSelector:@selector(emptyMethod)];
}
复制代码

实现forwardInvocation:

- (void)forwardInvocation:(NSInvocation *)anInvocation {SEL selector = [anInvocation selector];BOOL foundNilDelegate = NO;for (PPSDelegateNode *node in self.delegateNodes) {id nodeDelegate = node.delegate;if ([nodeDelegate respondsToSelector:selector]) {dispatch_async(node.delegateQueue, ^{[anInvocation invokeWithTarget:nodeDelegate];});} else if (nodeDelegate == nil) {foundNilDelegate = YES;//找到了delegate是空的node 需要移除掉}}if (foundNilDelegate) {NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];NSUInteger i = 0;for (PPSDelegateNode *node in self.delegateNodes) {id nodeDelegate = node.delegate;if (nodeDelegate == nil) {[indexSet addIndex:i];}i++;}[self.delegateNodes removeObjectsAtIndexes:indexSet];}
}
复制代码

注意 还有一个问题需要注意,要重写当前中间类的doesNotRecognizeSelector:方法,不然如果调用super的这个方法,会造成崩溃

demo地址:github.com/yangqian111…

欢迎关注公众号:

多delegate使用相关推荐

  1. 理解委托(delegate)及为什么要使用委托

    委托:是一种定义方法签名的类型. 当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联. 您可以通过委托实例调用方法. 上述为官方说法,理解起来比较难,举个生活中的例子: 某人有三子,让他们各 ...

  2. swift中delegate与block的反向传值

    swift.jpg 入门级 此处只简单举例并不深究,深究我也深究不来.对于初学者来说delegate或block都不是一下子能理解的,所以我的建议和体会就是,理不理解咱先不说,我先把这个格式记住,对就 ...

  3. 在请求完成后回调delegate的方法。然而回调时经常遇到这种情况:delegate已经被释放...

    最近的项目遇到了网络请求,需要在请求完成后回调delegate的方法.然而回调时经常遇到这种情况:delegate已经被释放,这时调用其方法则会引起crash. objc的runtime中有两种判断类 ...

  4. 异步使用委托delegate --- BeginInvoke和EndInvoke方法

    当我们定义一个委托的时候,一般语言运行时会自动帮委托定义BeginInvoke 和 EndInvoke两个方法,这两个方法的作用是可以异步调用委托. 方法BeginInvoke有两个参数: Async ...

  5. 对delegate进行扩展 打造通用的计时完成方法

    连接数据库是程序员经常要做的事情, 通常情况下, 需要连接SQL Server中哪个数据库是已知的, 用户在输入SQL Server的服务器IP.用户名.密码和数据库名字后, 如果所有信息输入正确, ...

  6. Swift - 委托(delegate)的介绍,及使用样例

    1,委托的说明 委托(delegate)是Cocoa的一个术语,表示将一个对象的部分功能转交给另一个对象. 比如对象A希望对象B知道将要发生或已经发生某件事情,对象A可以把对象B的引用存为一个实例变量 ...

  7. C#中Action与delegate、EventHandler的差异

    Action是一个泛型的委托,其内部即使用delegate去实现,当普通的delegate定义的参数与Action个数.类型一致时,两者实现的功能是一样的.只是Action的方式更加简洁.规范.如下: ...

  8. 【转】iOS开发-Protocol协议及委托代理(Delegate)传值

    原文网址:http://www.cnblogs.com/GarveyCalvin/p/4210828.html 前言:因为Object-C是不支持多继承的,所以很多时候都是用Protocol(协议)来 ...

  9. c# 带返回值的action_C#知识点讲解之C#delegate、event、Action、EventHandler的使用和区别...

    今天来讲一讲<C#delegate.event.Action.EventHandler的使用和区别> 目录 所以,event应运而生 所以,EventHandler应运而生 所以,Acti ...

  10. iOS视图控制器之间delegate传值

    2019独角兽企业重金招聘Python工程师标准>>> // ** *为了从ViewControllerB往回传值到ViewControllerA,我们需要使用协议(Protocol ...

最新文章

  1. Ajax Upload多文件上传插件翻译及中文演示
  2. Python之pypmml:pypmml的简介、安装、使用方法之详细攻略
  3. Description Resource Path Location Type Java compiler level does not match the version of the instal
  4. 在VS Code中执行SQL查询,是怎样一种体验?
  5. 罗切斯特大学排名计算机排名,罗切斯特大学排名
  6. Linux安装MySQL-MariaDB版本
  7. Membership、MembershipUser和Roles类
  8. 苹果mac三维动画设计渲染软件:Cinema 4D R20 (c4d r20)
  9. 简述MAC地址与IP地址的关系
  10. OPTEE的系统调用
  11. 【ChinaDRM】符合ChinaDRM GY/T 277-2019标准的码流分析系统
  12. SLAM学习——BA(Bundle Adjustment)与图优化
  13. webuploader 手机端上传图片默认打开相机 改为选择相册
  14. 浮山中学2021年高考成绩查询入口,浮山中学2019年高考成绩通报,第二波震撼来袭...
  15. 支付宝小程序-实名认证流程讲解
  16. Ubuntu 安装 uWSGI
  17. Linux——(1)基本命令
  18. origin9语言设置中文_Kali设置中文
  19. 仿知音漫画网站源码 PC+手机端 帝国cms7.5内核
  20. 设置 Linux 别名命令 alias 永久生效的方法

热门文章

  1. SQL Server 2005 在建立与服务器的连接时出错,错误26收藏
  2. Yahoo!的网站项目工作流程
  3. UA MATH566 统计理论 Fisher信息论的性质下
  4. Windows内核HAL相关学习
  5. layui 动态添加 表格数据
  6. seleniumIDE
  7. iOS:app直播---采集篇
  8. LINUX下安装ORACLE,完全搞定
  9. (兼容IE6)又一个提示框思密达,腾讯UED 201401242352
  10. 成功人士,默默做的30件事 (4-6)