iOS中的三种路由方案实践

原文地址
iOS中的三种路由方案实践
//www.greatytc.com/p/72d705ecc177

日常开发中,你可能会遇到这样的问题,各个模块相互引用,相互依赖,直观表现就是引入了很多头文件,很混乱,比如登录收藏消息模块间的相互调用,这样的代码显然不能符合 低耦合、高内聚、职责单一逻辑清晰的代码设计原则。
为此,我们可能需要使用一个 调度中心 去管理这些模块,有了这个调度中心,每个模块就不需要依赖其它模块,不用导入其它模块的头文件了,只需要调度中心关心每个模块的调度,其它模块只需要关心怎么调用和调用后反馈的结果,这个调度中心就是 路由(Router), 这种设计模式也被称为 中介者模式

下面我将从以下几个方面来介绍一下我学习到的关于路由的知识:

  1. 路由是什么
  2. 路由和组件化的关系
  3. 业界常见的三种解决方案
  4. 总结

路由是什么

路由简单来说就是一个中转站,输入一条数据,然后按照内部的一定规则,处理这条数据,最后输出特定格式的新数据。

1.网络层

从网络的角度来说,路由就是指路由器从一个接口收到数据包,根据数据路由包的目的地址进行定向并转发到另一个接口的过程。

2.服务器端

从服务器角度来说,当接收到客户端发来的 HTTP 请求时,会根据请求的URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。 在WEB开发中,路由就是URL函数的映射,在WEB开发中,Route是指根据URL找到处理这个URL函数Router 可以理解为一个容器,或者说是一种机制,它管理了一组Route

3.移动端

从移动端的角度来说,就是把URL映射到相应的上,iOS中的路由不是仅仅做页面跳转的,只是用的最多的地方,主要是因为可以解耦页面跳转的逻辑,它可以中转的不仅仅是 Controller还可以是其它对象,比如 UIImage

路由和组件化的关系

路由是一个很好的解耦的方案,它可以为各个组件之间调用提供遍历,没有路由,组件化也是可以用的。

业界常见的三种解决方案

1.Url-scheme注册(MGJRouter)

iOS系统中默认是支持 url scheme方式的,例如可以在浏览器中输入: weixin:// 就可以打开微信应用。自然在APP内部也可以通过这种方法来实现组件之间的路由设计。

这种方式实现的原理是在APP启动的时候,或者是向以下实例中的每个模块自己的load方法里面注册自己的断链(url),以及对外提供服务(Block),通过url-scheme标记好,然后维护在url-router里面。 url-router中保存了各个组件对应的url-scheme,只要其它组件调用了 open url 的方法,url-router就会去根据url去查找对应的服务并执行,详见demo。

1.1 URL的命名规范

遵循网上通用的 URIweb service模式的资源通用表示方式) 的格式,例如 appscheme://pathctd://home/scan

1.2 常见案例

1.2.1 JLRoutes git 上 star 最多的一个开源库

本质可以理解为保存一个全局的mapkeyurl,value是对应存放的block数组urlblock都会常驻在内存中,当打开一个url时,GLRoutes就可以遍历这个全局的map,通过url来执行对应的block

1.2.2 routable-ios
1.2.3 HHRouter
1.2.4 MGJRouter

蘑菇街的技术团队开源的一个router,特点是使用简单方便,JLRoutes的问题主要在于查找url的实现不够高效,通过遍历而不是匹配。还有就是功能偏多。HHRouterurl查找是基于匹配,所以会更高效,MGJRouter也是采用的这种方法,但它和viewcontroller绑定地过于紧密,一定程度上降低了灵活性。于是就有了 MGJrouter, 从数据结构上看它和 HHRouter是一样的。

蘑菇街方案不好的地方:

  1. URL注册对于实施组件化是完全没有必要的,拓展性和可维护性都降低;
  2. 基于 Open-url 的方案的话,有一个致命缺陷:非常规对象无法参与本地组件间调度;但是可以通过传递parms来解决,但是这个区分了远程调用和本地调用的接口;
  3. 模块内部是否仍然需要使用URL去完成调度?是没有必要的,为啥要复杂化?
  4. 当组件多起来的时候,需要提供一个关乎URL和服务的对应表,并且需要开发人员对这样一个表进行维护;
  5. 这种方式需要在APP启动时,每个组件需要到路由管理中心注册自己的URL及服务,因此 内存中需要保存这样一份表,当组件多起来以后就会出现一些内存的问题
  6. 混淆了本地调用和远程调用,它们的处理逻辑是不同的,正确的做法应该是把远程调用通过一个中间层转化成本地调用,如果把两者混为一谈,后期可能会出现无法区分业务的情况。比如对于组件无法响应的问题,远程调用可能直接显示一个404页面,但是本地调用可能需要做其它处理。如果不加以区分,那么就无法完成这种业务要求。 远程调用只能传递被序列化JSON的数据,像UIImage这样非常规的对象是不行的,所以如果组件接口要考虑远程调用,这里的参数与就不能是这类非常规对象

2.利用Runtime实现的target-action方式(CTMediator)- 推荐

相较于url-scheme的方式进行组件间的路由,runtime的方式借助了OC运行时的特征,实现了组件间服务的自动发现,无需注册即可实现组件间的调用,因此,不管从维护性、可读性、扩展性来说,都是一个比较完美的方案, 详见demo。

原理:

传统的中介者模式,这个中间件Mediator会依赖其它组件,其它组件也会依赖mediator, 但是能不能让mediator不在依赖组件,各个组件之间不再依赖,组件间调用只依赖中间者mediator
casa 大神是这样优化的:
利用target-action的方式,创建一个taget的类,里面定义了一些action方法,这些方法的结果是返回一个controller或其它object,再给中间件CTMedator添加一个分类方法,定义组件外部可调用的方法接口,内部实现方法 perform:target:action的方法,主要通过runtime中的 NSClassFromString 获取target类和 NSSelectorFromString 获取方法名,这样就可以执行先去创建的 target类中的方法得到返回值,再通过分类中的方法传值出去,完美解决~

3.protcol-class注册

通过协议绑定,核心思想和代理传值是一样的,遵循协议,实现协议中的方法,详见demo。

主要思路
1、创建一个头文件 CommonProtocol.h ,里面存放各个模块提供的协议。在各个模块依赖这个头文件,实现协议的方法。
2、创建一个中间类 ProtocolMediator, 提供模块的注册和获取模块的功能(其实就是将类和协议名进行绑定,放在一个字典里,key是协议名字符串,value是类)。
3、在各个模块中实现协议,核心代码如下:

Class cls = [[ProtocolMediator sharedInstance] classForProtocol:@protocol(B_VC_Protocol)];   
UIViewController<B_VC_Protocol> *B_VC = [[cls alloc] init];
[B_VC action_B:@"param1" para2:222 para3:333 para4:444];
[self presentViewController:B_VC animated:YES completion:nil];

参考文章

1、⾮常全⾯的讲解了各大路由方案
2
3

总结

通过这次对路由方案的研究,认识到了自己对系统架构方面的认识还是太少,以前并没有认真考虑怎么去设计一个好代码,我们需要的事写一些优质代码,牢记 低耦合、高内聚、职责单一逻辑清晰,不能甘心做码农,只知道堆代码!!!

本文Demo地址:点我 CXRouterDemo

</article>

4人点赞

iOS

作者:georrychen
链接://www.greatytc.com/p/72d705ecc177
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339