面试资料iOS学习我爱编程

iOS路由简说

2018-04-14  本文已影响928人  欢博

一、概念

        路由就是URL到函数的映射;对于客户端来说,就是把URL映射到响应的类或者controller。

        如何能把URL映射到我们已经开发的类或者controller中呢,这就需要我们首先要为其添加一个配置表,该配置表定义了URL的规则和映射的目标。

二、路由能解决哪些问题

1、 降低App页面之间的耦合性。随着项目越来越负责,各个组件和页面之间的跳转也变得越来越复杂,他们之间的跳转逻辑也变的越来越紧密,这就造成了各个模块的相互依赖越来越紧密

2、 统一各个端(iOS、Android、Web)之间实现跳转页面的统一性

3、 可以通过动态下发配置表来配置App的跳转逻辑。这样iOS和Android两边只要共用一套配置文件,通过下发修改后配置表也能实现动态的改变映射目标。

三、资源的定义

在Android与iOS系统中,均支持URL Scheme,通过app内协定的Scheme,进行唤醒app和参数的传递。例如QQ(mqq://)、支付宝(alipay://)等。

四、实现的流程

1、路由的流程实现,如下图所示,我们确定路由需要做哪些事 

1.1 A模块调用路由,为表达自己需要调用的是B模块,考虑到H5、推送以及其他App 的外部调用,可以使用URL这种方式来定义目标,也就是说用URL来表示目标B

1.2对一个URL的请求来说,路由需要有统一的回调处理,当然,如果不需要回调也是可以的,回调是需要目标去触发的

1.3路由要有处理URL的功能,并调用其他模块的能力

2、路由的逻辑结构

五、路由的使用

        以下是我从Github上面找的一些路由方案,按照Star从高到低排列。依次来分析一下它们各自的设计思路。

1、WLRRoute

1.1类图结构

1.2 类说明:

(1)WLRRouteRequest,路由层的请求,无论是跨应用的外部调用还是内部调用,最后都形成一个路由请求,该请求包含了URL上的queryparameters和路径参数,还有内部调用时直接传入的原生参数,还有请求发起者对目标预留的回调block。

(2)WLRRouteHandler,路由层的handler处理,handler接收一个WLRRouteRequest对象,来完成是否是界面跳转,还是组件加载,还是内部逻辑。

(3)WLRRouter,路由核心对象,内部持有注册的Handler和匹配Matcher;负责界面跳转的Handler,负责组件加载的Handler,负责API的Handler;负责URL匹配的Matcher,则是则是处理请求函数和路径信息。路由的作用就是将外部调用传入的URL或者是内部调用传入的target,在内部匹配上对应的handler,然后调用生命周期方法,完成处理过程,当然,图中还有route的中间件,实际上是预留AOP的口子,方面后期扩展。

(4)WLRRouteMatcher,用以处理外部调用的URL是否能与预设的正则表达式匹配,每一个匹配规则对应一个WLRRouteMatcher, 在WLRRouter中,每一次注册一个规则都会生成一个WLRRouteHandler和WLRRouteMatcher与之对应。

(5)WLRRegularExpression,继承NSRegularExpression,用以匹配URL,WLRRouteMatcher内部有一个WLRRegularExpression对象,WLRRouteMatcher接受一个URL,会使用WLRRegularExpression生成一个WLRMatchResult对象,来确定是否匹配成功,如果匹配成果则将URL上的路径参数给取出来。

(6)WLRMatchResult,用以描述WLRRegularExpression的匹配结果,包含路径参数和请求参数。

1.3工作流程

(1)App启动实例化WLRRouter对象

(2)实例化WLRRouteHandler对象和匹配规则表达式

(3)WLRRouter对象挂载URL的表达式相对应WLRRouteHandler实例,同时根据匹配规则生成一个WLRRouteMatcher对象,用以处理符合此规则的URL。

(4)外部调用的URL和callback传入WLRRouter对象

(5)WLRRouter对象遍历内部持有的URL的匹配表达式,并找到每一个WLRRouteMatcher对象,将URL传入看是否能返回WLRRouteRequest对象

(6)将WLRRouteRequest对象传入对应的WLRRouteHandler对象。

(7)WLRRouteHandler对象根据WLRRouteRequest寻找到TargetViewController和SourceViewController,在生命周期函数里,完成参数传递与视图转场。

1.4调用实现

(1)实现WLRUserHandler继承WLRRouteHandler,用于实现目标对象处理跳转,主要对以下方法进行重写:

//handle处理一个请求

- (BOOL)shouldHandleWithRequest:(WLRRouteRequest *)request;

//根据request取出调用的目标视图控制器

-(UIViewController *)targetViewControllerWithRequest:(WLRRouteRequest *)request;

//根据request取出来源的视图控制器

-(UIViewController *)sourceViewControllerForTransitionWithRequest:(WLRRouteRequest *)request;

//开始进行转场

-(BOOL)transitionWithRequest:(WLRRouteRequest *)request error:(NSError *__autoreleasing *)error;

       (2)注册路由规则和处理handle

self.router = [[WLRRouter alloc]init]; 

[self.router registerHandler:[[WLRUserHandler alloc]init] forRoute:@“/user/:phone([0-9]+)"];

           也可以通过添加Block的为处理handle,如下

[self.router registerBlock:^WLRRouteRequest *(WLRRouteRequest *request) {  return request } forRoute:@“/user/:phone([0-9]+)”];

说明:该request中含有URL匹配解析出的路由参数和请求参数,分别为routeParameters和queryParameters;另primitiveParams为原生调用时的传值

     (3)当通过Scheme唤起app或者通过直接调用路由进行跳转时调用下面方法实现:

          [self.router handleURL:[NSURL URLWithString:@“scheme://myapp/user/13500000000"] primitiveParameters:@{@"user":@"nihao"}  targetCallBack:^(NSError *error, id responseObject) { NSLog(@"UserCallBack"); } withCompletionBlock:^(BOOL handled, NSError *error) { NSLog(@"UserHandleCompletion"); }];

其中primitiveParameters为app内调用跳转时指定数据,可为空;targetCallBack:为目标匹配的回调;withCompletionBlock:执行完跳转的回调。

2、JLRoutes

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

2.1 JLRoutes类说明

(1)routeControllersMap 是全局的单例可变字典。

(2)这个字典的 key 值对应一个标识,源码中称之为 scheme,为了不混淆,咱们就叫其为 JLRoutes 对象标识。这个标识对应的value 值为 routesController(JLRoutes类的对象:JLRoutes *routesController)。

(3)JLRoutes的对象(routesController)有很多属性,常用的有两个属性:NSString *scheme:也就是上面所说的 JLRoutes对象标识,也就是说,此 value 值记录了自己的 key 值。

(4)NSMutableArray *routes:此数组中存放了JLRRouteDefinition 对象。

(5)JLRRouteDefinition 对象为最终的具体模型,也就是说你注册的跳转逻辑的所有信息,都存在于这个模型中,包括要实施操作的handlerBlock(执行操作的block代码块)、scheme(JLRoutes对象标识)、pattern(模式)、priority(优先级)。

2.2工作流程

(1)App启动根据Scheme实例化JLRoutes对象和添加路由规则,一个规则对应一个JLRoutes对象,存储在全局routeControllersMap中。

(2)外部调用时,实例化JLRRouteRequest对象并解析出路径参数和请求参数存放在pathComponents和queryParams中。

(3)通过遍历routeControllersMap中的JLRoutes对象,找出能匹配URL规则的JLRoutes,同时返回匹配结果JLRRouteResponse。

(4)最后调用调用JLRoutes的处理结果的Block,由实现者实现目标的跳转。

2.3调用实现

(1)注册路由Scheme和添加路由规则

[[JLRoutes routesForScheme:@“RouteOne"]addRoute:@"/:phone" handler:^BOOL(NSDictionary * parameters) {

//处理匹配结果 进行跳转

                return YES;

    }];

(2)由JLRoutes调用routeURL传入URL,根据URL创建JLRRouteRequest并解析出路由路径和请求参数。

(3)匹配JLRoutes的匹配规则,取出路径上的有效参数

(4)调用跳转的处理Block,进行页面的目标跳转

3、WLRRoute 和 JLRoutes的差异化

3.1 JLRoutes 

(1)缺乏规则匹配的能力,不支持正则表达式匹配。

(2)代码逻辑简单,容易上手,不需要重写处理类。

(3)路由规则跳转逻辑为Block实现。

(4)各个业务模块间的耦合性高。

(5)调用时需指定使用的Scheme,

3.2 WLRRoute 

(1)具有强大的匹配能力,支持正则表达式的匹配。

(2)每个路由规则都对应一个Handle类,所以需重写其handle处理类,也可指定Block来定制跳转的目标页面。

(3)各个业务模块间的耦合性低

(4)调用时无需指定使用的Scheme,会自动匹配规则

上一篇 下一篇

猜你喜欢

热点阅读