

iOS 一对多 delegate 的简单应用
source link: http://www.daizi.me/2019/02/26/iOS 一对多 delegate 的简单应用/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在之前我们尝试过 hook webView 的 delegate,可以查看【 iOS 如何优雅地 hook 系统的 delegate 方法 】。当时的思路是,由于 delegate 只能是一对一的消息传递,后面设置的 delegate 对象会替换前面设置的 delegate 对象,因此在无入侵的情况下,需要通过 setDelegate 方法找到设置的 delegate 对象,然后 hook 该对象实现的 protocol 方法,这种方法迂回且比较容易出问题(过多操作运行时)。
现在我们可以通过更简单的方式来实现,在 hook webView 的初始化方法后,使用一对多委托方式,将 webView 的 delegate 设置为我们内部实现相关协议的对象,使得我们的 hook 代码不影响原始代码的 delegate 实现。
启发
为什么突然想到可以这样来实现功能?其实启发是来源于优秀的开源框架 WebViewJavascriptBridge ,WebViewJavascriptBridge 可以简洁优雅地实现原生和 JS 通信。
WebViewJavascriptBridge 在 Native 端实现桥接功能的简化流程是: JS 向 Native 发消息是构造特殊的 url request,由 Native 端拦截并解析 URL 请求来实现通信。那么一定会需要 webView 拦截 URL( webView:decidePolicyForNavigationAction:request:frame:decisionListener:
) 的回调来处理。
那么如何在 delegate 只能一对一传递的情况下,既保证原始的 delegate 实现,又能在 WebViewJavascriptBridge 内部实现 delegate 的回调?
走进源码
我们可以猜想,WebViewJavascriptBridge 一定使用了某种有效方式解决了这个问题。接下来让我们走进源码来看具体的实现:
1、在桥接类的初始化方法中,将 webView 实例对象传入,并设置其 delegate 为桥接类。(这时候如果外部的控制器提前设置了 delegate 会被覆盖失效)
WebViewJavascriptBridge*bridge; _bridge = [WebViewJavascriptBridgebridgeForWebView:webView];
2、如果调用方也想作为 delegate 代理,不能通过设置 webView 的 delegate 来实现,这样会覆盖上面桥接类的 delegate,导致桥接类无法正常工作,WebViewJavascriptBridge 的做法是将待设置 delegate 对象传入桥接类,并赋值给 _webViewDelegate
(weak 变量,在 self 释放后可以随即设置为 nil,不会造成循环应用)。
[_bridge setWebViewDelegate:self];
- (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate { _webViewDelegate = webViewDelegate; }
3、在桥接类对应 delegate 方法回调时,调用 _webViewDelegate 相应的实现方法,
- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener { // another handler if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { [_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; } }
扩展及总结
如果想实现不入侵地实现一对多 delegate,可以通过 hook webView 初始化方法以及 setDelegate 方法,并注意设置 delegate 的时机,防止被覆盖而失效。
另外,WebViewJavascriptBridge 的实现实际上是一对二的代理,虽然对我来说已经够用了。但如果有同学想扩展为一对多 delegate,可以尝试实现一个桩类,将桩类设置为 delegate,并使用数组管理其他想实现 delegate 协议的对象,实现一对多 delegate。
现在回过头看这种实现很简单易懂,但是在之前固定思维的限制下,使用了大量繁杂、迂回且不可靠的方式,所以多看这些优秀框架的源码,可以获得很多思考、设计、解决问题的思路。
Recommend
-
38
MySQL(11) 纪录一次left join一对多关系而引起的bug 我们有一个 订单表 和 一个 物流表 它们通过 订单ID 进行一对一的关系绑定。但是由于物流表在保存订单信息的时候没有做判断该订
-
52
在关系型数据库中,随处可见表之间的连接,对级联的表进行增删改查也是程序员必备的基础技能。关于Spring Boot整合Mybatis在之前已经详细写过,不熟悉的可以回顾Spring Boot整合Mybatis并完成CRUD操作,这是本文操作的基础。本文先准备一个测试的数据库,然后使用M...
-
19
1. 前言 MySQL一对多的数据分页是非常常见的需求,比如我们要查询商品和商品的图片信息。但是很多人会在这里遇到分...
-
12
上篇随笔《ABP框架中一对多,多对多关系的处理以及功能界面的处理(1)》介绍了一对多关系下的主从表数据处理,包括ABP框架对EF实体、DTO等关系处理,以及应用层基类接口的调整和Apicaller调...
-
12
在我们开发业务的时候,一般数据库表都有相关的关系,除了单独表外,一般还包括一对多、多对多等常见的关系,在实际开发过程中,需要结合系统框架做对应的处理,本篇随笔介绍基于ABP框架对EF实体、DTO关系的处理,以及提供对应的接口进行相关的数据保存更新操作...
-
5
法律界首场“一对多”人机竞赛开打 AI律师合同审核技能超越人类 2020年12月05日 15:34 891 次阅读 稿源:
-
11
注:代码已托管在GitHub上,地址是: https://github.com/Damaer/Mybatis-Learning ,项目是 mybatis-10-one2many ,需要自取,需要配置 maven 环境以及 mysql 环境( sql
-
12
百万汉字注解 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< Gitee
-
8
使用awk查找并修复数据中一对多的不一致问题 从 https://www.datafix.com.au/BASHing/2021-03-17.html 上看到的一个 awk 小技巧。 所谓“一对多”的不一致问...
-
2
摘要:本文通过分析鸿蒙轻内核事件模块的源码,深入掌握事件的使用。 本文分享自华为云社区《
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK