iOS开发笔记之七十五——轻量级组件化路由方案XYPageMaster(一)

******阅读完此文,大概需要15分钟******

一、项目背景

一套完备的路由方案是推进VivaVideo产品的组件化进程前提,为了能够为VideoVideo量身定做一套适合自己的路由方案,我做了一定的调研分析,我特意找了市场几款主流的路由方案进行简单的分析比对,希望可以集各家所长,它们有JLRouter、MGJRouter、CTMediator等,分析的比较浅陋,如有不准确的地方,可以及时留言指出;

二、JLRouter

JLRouter是一个纯粹的URL路由管理库,主要分为路由URL的注册、解析、匹配等功能,它以较少的代码处理了业务中最为复杂的URL规则。也就是说,JLRouter的URL规则非常灵活,可以应对最为复杂的业务场景,例如美团、阿里这种垂直业务繁多的App,每个业务线都可以用JLRouter灵活定制自己的URL规则。它具有如下特点:

1、URL解析规则遵循标准的NSURL格式

(备注:The URLs employed by the NSURL class are described in RFC 1808RFC 1738, and RFC 2732.)

标准的NSURLComponent各个字段如下:

JLRouter会传入每个字符串,都会按照上面的样子进行切分处理,分别根据RFC的标准定义,取到各个NSURLComponent。

2、非常灵活的URL解析规则

(1)scheme名称可以有多个

iOS系统默认是支持URL Scheme的,就是我们可以根据tel://110这种格式像打开网页一样唤起并打开一个App,一款App的Scheme一般是唯一的。但是对于一些组件化程度非常高的场景,也许可以有多个Scheme的应用场景,例如,美团酒旅事业部,与美食事业部、结婚事业部、外卖事业部等垂直业务并行,在美团App里面有自己独立的业务入口,但是他们也有自己的独立App产品家族,此时酒旅事业部可以统一维护一个独立的路由scheme。

(2)ueser information + host + path区域字段可以灵活配置

接上,酒旅事业部下属也有酒店、景点、度假等子业务,子业务下面还有更细的子业务,这些子业务也可以维护自己的路由规则,所以他们可以在ueser information + host + path区域配置自己的路由规则;

3、JLRouter所有的跳转入口统一处理

JLRouter的跳转处理逻辑如下:

用openURL:方式打开url方式,可以将所有的入口集中在- (BOOL)application:openURL:options:options中处理,比较简单便捷;

4、灵活的优先级配置

每条路有都可以配置优先级,JLRouter查找时会优先匹配优先级高的路由;

5、JLRouter本身不提供跳转逻辑,具体的跳转逻辑需要业务方自己提供;

前面说过,JLRouter本身是一个单纯的URL路由管理功能,不提供viewController的push以及pop操作,这些代码需要App自己添加与处理;类似的如下:

6、JLRouter没有独立的正向传值和反向传值处理逻辑

如果A页面跳转到B页面,B需要A传递的值,这是需要业务自己写逻辑将A的值传递给B。如果A需要B的值回传,也需要业务自己写代码处理。业务自己添加代码处理,不同的开发人员可以灵活采取不同方式处理,会增加业务代码的复杂性。

7、JLRouter的注册逻辑比较灵活,业务可以在任意地方添加url注册代码

这就意味着,JLRouter注册逻辑在可以出现在业务代码的任意地方,不同的开发人员按照自己的需要和理解,添加自己的逻辑,这样对业务代码的侵入性更强,加大业务代码的复杂性。

8、JLRoutes路由的查找匹配逻辑效率不高

在JLRoutes类中,有以下代码:

for (JLRRouteDefinition *route in [self.mutableRoutes copy])
{
// check each route for a matching response
    JLRRouteResponse *response = [route routeResponseForRequest:request     decodePlusSymbols:shouldDecodePlusSymbols];
    if (!response.isMatch) {
        continue;
    }
    [self _verboseLog:@"Successfully matched %@", route];
    if (!executeRouteBlock) {    
    // if we shouldn't execute but it was a match, we're done now
        return YES;
    }
// configure the final parameters

for循环遍历数组,时间复杂度O(n)。

9、参考资料

https://www.cnblogs.com/oc-bowen/p/6489070.html

三、MGJRouter

MGJRouter是HHRouter的升级版,它本身也是一个纯粹的router,它的使用大致如下:

1、被跳转页面的注册:

2、入口处代码如下:

只要简单地完成以上两步,就可以页面的Router解析、数据传递、跳转;代码总体比较简单,url结构清晰。

与此同时,MGJRouter也支持url的注销操作,deregisterURLPattern:

3、MGJRouter的URL解析规则遵循标准的NSURL格式,这一点同JLRouter;

4、MGJRouter的支持参数的正向传递,block反向传递;

参数可以直接拼在url后面,也可以通过设置userInfo的方式。MGJRouter本身具有灵活的block传递功能;

5、MGJRouter的scheme格式也非常灵活,可以设置多个;

你可以注册mgj://的url或者mgj1://格式的url,均可跳转;另外,还支持中文的匹配(没啥意义);

6、MGJRouter的路由匹配是查找字典,时间复杂度:O(1),相比JLRouter较高;

7、MGJRouter的路由解析规则其实可以不仅限于viewcontroller,可以用于任意对象类的通讯;

8、MGJRouter页面路由的注册在业务页面中注册,意味着业务可以灵活配置自己的url规则,可以在+load或者其他较早的时机进行注册。

不利于url的统一管理,+load的无限制扩展,最终会给app启动带来负担;另外,由于业务的不断扩张,启动注册的页面越来愈多,注册表也会越来越大,这部分常驻的内存其实是一个不必要的开销;

参考文档:https://www.cnblogs.com/oc-bowen/p/6489070.html

四、CTMediator

1、CTMediator是一个基于Mediator模式和Target-Action设计模式,中间采取了runtime来完成调用而实现的组件库,这套组件化方案将远程调用和本地调用做了拆分,远程采取解析url的方式,本地调用采取Mediator方式进行调用,阿里的BeeHive也是参考了这类设计模式;

2、CTMediator无需启动注册,所以内存性耗比起MGJRouter要低,但是CTMediator采取了硬编码的方式给ViewController写一些“中介”代码,过程如下:

例如AViewController需要实现跳转解耦,首先需要在AViewController所在的项目中建立一个“接口”类:Target_A,这个类就是CTMediator查找AViewController的关键类:

- (UIViewController *)Action_viewController:(NSDictionary *)params
{
    AViewController *viewController = [[AViewController alloc] init];
    return viewController;
}

然后你还需要建立一个为AViewController所在项目服务的Pod:A_Category,针对AViewController的扩展代码:

- (UIViewController *)A_aViewControllerWithCallback:(void(^)(NSString *result))callback;
{
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    params[@"callback"] = callback;
    return [self performTarget:@"A" action:@"viewController" params:params shouldCacheTarget:NO];
}

当然以后AViewController中其他ViewController需要支持跳转,可以直接在Pod:A_Category中继续添加扩展方法。入口处跳转代码如下:

UIViewController *viewController = [[CTMediator sharedInstance] A_aViewControllerWithCallback:^(NSString *result) {

}];
[self.navigationController pushViewController:viewController animated:YES];

3、CTMediator在本地逻辑上加了url解析,即可实现远端调用。

4、CTMediator相比MGJRouter对业务代码的侵入性较小,但是由于需要额外硬编码一些“中介”代码,对App整体项目的侵入性更大(每个项目都要标配一个扩展)。

5、无需启动注册,利用runtime匹配目标viewcontroller,设计巧妙,内存查找性能更优,但是接入成本以及维护成本较urlmapping方式较大,后期的可扩展性也较差。

6、runtime找到目标viewcontroller,意味着业务viewcontroller方法的className命名必会受限,不够灵活。

7、远端调用和本地调用的区分,url统一注册的方式默认是没有作区分的,但是对于url调用来说,如果业务需要这其实就是一个参数的问题就能解决。

8、相比urlmapping注册的方式,启动的性耗,在我们工具类产品中,可以忽略不计,即使以后urlmapping文件膨胀了,我们也可以采取分级加载的方式来优化。

参考资料:https://casatwy.com/iOS-Modulization.html

五、XYPageMaster的使命

1、本身具有JLRouter和MGJRouter的基本的URL路由管理功能;由于小影家族的App和电商类App不同(拥有众多的垂直业务),工具类的页面VC不会有太多,Url不需要进行灵活的分级,要尽可能的简单易懂,数据格式可跨多平台,与android统一、H5统一;推荐格式如下:

xiaoying://tools?id=123456&index=1

2、支持数据基本数据类型的参数的正向传递、反向传递(可引入XYReactBlackBoard);

3、支持app内部、外部跳转(是否需要区分内外部跳转),并且多种方式跳转的统一处理,可参考JLRouter;

4、统一的url、viewcontroller映射管理、归档功能,启动注册;

5、由于业务层navigationContorller的使用比较混乱(维护了多navigationContorller),XYPageMaster还要接管navigation功能,全局统一并且唯一的navigation,更好的navigation管理,可以支持常见的push、pop操作,以后可以支持CATransition等转场动画的定制;

6、即然具有了navigator的相关功能,也要对相同类页面的重复push堆栈进行管理,尤其针对首页需要有开关控制;

7、需要考虑到快速连续多次push页面、线程保护等问题;

8、向前兼容支持storyboard、xib等历史页面的跳转;

9、支持动态调度;

10、支持VC缓存等;

11、比较人性化的业务接入方式、比较灵活的业务可扩展性;

基于如上业务诉求,我汲取了多家路由的feature,开发了轻量级的XYPageMaster路由框架,详见下篇文章:https://mp.csdn.net/postedit/82286690

猜你喜欢

转载自blog.csdn.net/lizitao/article/details/82223468