最后更新: 2018-1-20

JLRoutes 是在 github 上 Star 比较多的一个, 在各大平台也有介绍, 一些知识可以参考到下面的连接查看. 本文仅仅作为我的思考以及对应的心得;

一、 JLRoutes如何管理URLScheme以及对应的Handler

当调用 [JLRoutes globalRoutes]; 时候, 回去调用 + (instancetype)routesForScheme:(NSString *)scheme;, 想起代码如下;

static NSMutableDictionary *routeControllersMap = nil;

+ (instancetype)globalRoutes
{
return [self routesForScheme:JLRoutesGlobalRoutesScheme];
} + (instancetype)routesForScheme:(NSString *)scheme
{
JLRoutes *routesController = nil; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
routeControllersMap = [[NSMutableDictionary alloc] init];
}); if (!routeControllersMap[scheme]) {
routesController = [[self alloc] init];
routesController.scheme = scheme;
routeControllersMap[scheme] = routesController;
} routesController = routeControllersMap[scheme]; return routesController;
}

有上面可以看出, 实例化一个 JLRoutes之后,会生成一个 routeControllersMap 全局静态字典,key为URL scheme, Value 为JLRoutes 对象, JLRoutes 对应的 Scheme 唯一,但是对应的 Routes 可以有多个.

总结: JLRoutes 使用键值对形式保存;

二、JLRoutes 如何注册 URL Scheme

  1. 普通的url Scheme,
[[JLRoutes routesForScheme:@"JLRoutesOne"] addRoute:@"/:ViewController/:userID/:pass" handler:nil]

最终会生成一个 JLRRouteDefinition 对象, 里面包含了 scheme = JLRoutesOnepattern= /:ViewController/:userID/:passpriority 以及 patternComponents = [:ViewController, :userID, :pass] 还有 对应的回调 handlerBlock;

其实我们可以看出, JLRRouteDefinition 对象 已经保存了所有 URL相关的信息。

然后将 JLRRouteDefinitionJLRoutes 根据优先级对象管理起来; [self.routes addObject:route];

  1. 包含可选参数的URL;
[[JLRoutes globalRoutes] addRoute:"/path/:thing/(/a)(/b)(/c)" handler:nil]
+ (NSArray <NSString *> *)expandOptionalRoutePatternsForPattern:(NSString *)routePattern
{
/* this method exists to take a route pattern that is known to contain optional params, such as: /path/:thing/(/a)(/b)(/c) and create the following paths: /path/:thing/a/b/c
/path/:thing/a/b
/path/:thing/a/c
/path/:thing/b/a
/path/:thing/a
/path/:thing/b
/path/:thing/c
*/ if ([routePattern rangeOfString:@"("].location == NSNotFound) {
return @[];
} NSString *baseRoute = nil; // 分析点1:
NSArray *components = [self _optionalComponentsForPattern:routePattern baseRoute:&baseRoute];
// 分析点2
NSArray *routes = [self _routesForOptionalComponents:components baseRoute:baseRoute]; return routes;
}

分析点1:

通过 NSSCanner来解析开数据, 拆解可选部分与必选部分, baseRoute 为必选部分,components 为可选部分;

baseRoute = /path/:thing/
components = ["/a", "/b", "/c"]

分析点2:

此处就是将 components 拼接成一个个的url;

<__NSFrozenArrayM 0x60400024b370>(
/path/:thing//a/b/c,
/path/:thing//b/c,
/path/:thing//a/c,
/path/:thing//c,
/path/:thing//a/b,
/path/:thing//b,
/path/:thing//a,
/path/:thing/
)

深入进去还是比较有意思的,我们进去看看:

运用递归的想法.

逐步解析一下:

/c [/a, /b]

/b [/a]

/a []

递归回去

[[/a], []]

[[/a], [], [/a, /b], [/b]]

[[/a], [], [/a, /b], [/b], [/a, /c], [/c], [/a, /b, /c], [/b, /c]]

解析出来之后,将数组中的每一项,生成一个 JLRRouteDefinition 对象, 然后由 JLRoutes.routes来管理;

- (NSArray<NSArray *> *)JLRoutes_allOrderedCombinations
{
NSInteger length = self.count;
if (length == 0) {
return [NSArray arrayWithObject:[NSArray array]];
} id lastObject = [self lastObject];
NSArray *subarray = [self subarrayWithRange:NSMakeRange(0, length - 1)];
NSArray *subarrayCombinations = [subarray JLRoutes_allOrderedCombinations];
NSMutableArray *combinations = [NSMutableArray arrayWithArray:subarrayCombinations]; for (NSArray *subarrayCombos in subarrayCombinations) {
[combinations addObject:[subarrayCombos arrayByAddingObject:lastObject]];
} return [NSArray arrayWithArray:combinations];
}

三、 JLRoutes 调用

系统调用 OpenUrl,因为注册的Scheme为当前app 使用,因此会调用到 AppDelegate

-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
return [JLRoutes routeURL:url];
}

查看源代码,可以追溯到 -_routeURL:withParameters:executeRouteBlock:.

  1. 会根据url生成对应的 JLRRouteRequest; 将url进行一些列的拆分; host & Path & query

  2. 遍历 JLRoutes.routes里面的 JLRRouteDefinition, 判断能否根据 JLRRouteRequest来匹配,生成对应的 JLRRouteResponse,

    匹配规则比较简单,根据前面的 : *来设置;

  3. JLRoutes 还支持通配符;


四: 总结:

JLRoutes 相对来设比较简单的一个框架,但是实用性非常的高, 作者用一个全局的Map来保存对应的Scheme信息,解析 Url 成一个 request, 根据是否匹配生成对应的response, 然后进行设置。

设置很巧妙,

但是这个好像存在几个问题:

  1. 全局保存,如果成指数型的增长,可能占用较大内存;
  2. 对所有的handler 都需要提前注册进去

此框架使用了 NSSCanner 以及 NSURLCompenent

相关链接:

1. 官方的JLRoutes链接;

2. 我阅读的版本,已经fork过来

3. 可参考demo

源码阅读-JLRoutes路由设置的更多相关文章

  1. Yii2.0源码阅读-从路由到控制器

    之前的文章弄清了一次请求的开始到结束.主要讲了Yii Applicaton实例的创建.初始化,UrlManager如何返回Yii中的路由信息,到runAction,最后将Response发送给客户端. ...

  2. laravel5.5源码阅读草稿——路由

    laravel 里的路由是由RouteServiceProvider提供的,其中的boot方法为启动项,调用了父类的boot方法. RouteServiceProvider中的boot方法设置了自己与 ...

  3. Kibana源码分析--Hapijs路由设置理解笔记

    [ES6解构赋值]:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_ ...

  4. Hadoop 副本放置策略的源码阅读和设置

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/hadoop_block_placement_policy 大多数 ...

  5. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  6. 40 网络相关函数(八)——live555源码阅读(四)网络

    40 网络相关函数(八)——live555源码阅读(四)网络 40 网络相关函数(八)——live555源码阅读(四)网络 简介 15)writeSocket向套接口写数据 TTL的概念 函数send ...

  7. 36 网络相关函数(四)——live555源码阅读(四)网络

    36 网络相关函数(四)——live555源码阅读(四)网络 36 网络相关函数(四)——live555源码阅读(四)网络 简介 7)createSocket创建socket方法 8)closeSoc ...

  8. 33 网络相关函数(一)——live555源码阅读(四)网络

    33 网络相关函数(一)——live555源码阅读(四)网络 33 网络相关函数(一)——live555源码阅读(四)网络 简介 1)IsMulticastAddress多播(组播)地址判断函数 多播 ...

  9. gogs 源码阅读笔记 001

    gogs 源码阅读笔记 001 gogs项目相当不错,本笔记实际是基于gogs fork版本 git-122a66f. gitea (gitea版本由来)[https://blog.gitea.io/ ...

随机推荐

  1. FTP服务器的搭建(CentOS 7)

    注意ip地址为: 虚拟机ip设置 TYPE="Ethernet"BOOTPROTO="static"NAME="enp0s3"DEVICE= ...

  2. Anaconda折腾记(1)

    Anaconda折腾记 谨此记录小白的我在Anaconda里面的摸爬滚打 更换更新源 可以不使用命令,直接进入C盘,进入user文件夹,进入当前的用户文件夹下,记得显示隐藏文件. 找到.condarc ...

  3. E - 秋实大哥与战争

    秋实大哥与战争 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit S ...

  4. Exchange 2010 详细安装步骤

    工具/原料   系统要求:windows 2008 R2 标准版或者企业版 Exchange Server 2010 SP3:https://www.microsoft.com/en-us/downl ...

  5. hadoop批量命令脚本xrsync.sh传输脚本

    1.xrsync.sh脚本 #!/bin/bash if [[ $# -lt 1 ]] ; then echo no params ; exit ; fi p=$1 #echo p=$p dir=`d ...

  6. join 与 countdownlatch 的区别 扩展 栅栏 CyclicBarrier

    我们先看一个 小例子 , 使用 join 与CountDownSlatch 都可以完成 当1,2线程 完全结束后 3 线程 start 对比我们就能够知道 CountDownSlatch 比 JOIN ...

  7. iOS 10 下 Plus 启动APP 导致Icon 铺满全屏问题

    1.解决方法,添加LacuchScreen 启动图需要手动适配 http://stackoverflow.com/questions/39571694/ipad-application-shows-a ...

  8. Shiro多Realm验证

    在单Realm的基础上,进行如下内容的修改 原有的ShiroRealm.java: package com.atguigu.shiro.realms; import org.apache.shiro. ...

  9. php通过反射方法调用私有方法

    PHP 5 具有完整的反射 API,添加了对类.接口.函数.方法和扩展进行反向工程的能力. 下面我们演示一下如何通过反射,来调用执行一个类中的私有方法: <?php //MyClass这个类中包 ...

  10. python语音提示

    #coding:utf8 import win32com.client speaker = win32com.client.Dispatch("SAPI.SpVoice") whi ...