源码阅读-JLRoutes路由设置
最后更新: 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
- 普通的url Scheme,
[[JLRoutes routesForScheme:@"JLRoutesOne"] addRoute:@"/:ViewController/:userID/:pass" handler:nil]
最终会生成一个 JLRRouteDefinition 对象, 里面包含了 scheme = JLRoutesOne、pattern= /:ViewController/:userID/:pass、priority 以及 patternComponents = [:ViewController, :userID, :pass] 还有 对应的回调 handlerBlock;
其实我们可以看出, JLRRouteDefinition 对象 已经保存了所有 URL相关的信息。
然后将 JLRRouteDefinition 让 JLRoutes 根据优先级对象管理起来; [self.routes addObject:route];
- 包含可选参数的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:.
会根据url生成对应的
JLRRouteRequest; 将url进行一些列的拆分;host&Path&query遍历
JLRoutes.routes里面的JLRRouteDefinition, 判断能否根据JLRRouteRequest来匹配,生成对应的JLRRouteResponse,
匹配规则比较简单,根据前面的 : *来设置;JLRoutes 还支持通配符;
四: 总结:
JLRoutes 相对来设比较简单的一个框架,但是实用性非常的高, 作者用一个全局的Map来保存对应的Scheme信息,解析 Url 成一个 request, 根据是否匹配生成对应的response, 然后进行设置。
设置很巧妙,
但是这个好像存在几个问题:
- 全局保存,如果成指数型的增长,可能占用较大内存;
- 对所有的handler 都需要提前注册进去
此框架使用了 NSSCanner 以及 NSURLCompenent
相关链接:
1. 官方的JLRoutes链接;
2. 我阅读的版本,已经fork过来
3. 可参考demo
源码阅读-JLRoutes路由设置的更多相关文章
- Yii2.0源码阅读-从路由到控制器
之前的文章弄清了一次请求的开始到结束.主要讲了Yii Applicaton实例的创建.初始化,UrlManager如何返回Yii中的路由信息,到runAction,最后将Response发送给客户端. ...
- laravel5.5源码阅读草稿——路由
laravel 里的路由是由RouteServiceProvider提供的,其中的boot方法为启动项,调用了父类的boot方法. RouteServiceProvider中的boot方法设置了自己与 ...
- Kibana源码分析--Hapijs路由设置理解笔记
[ES6解构赋值]:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_ ...
- Hadoop 副本放置策略的源码阅读和设置
本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/hadoop_block_placement_policy 大多数 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
- 40 网络相关函数(八)——live555源码阅读(四)网络
40 网络相关函数(八)——live555源码阅读(四)网络 40 网络相关函数(八)——live555源码阅读(四)网络 简介 15)writeSocket向套接口写数据 TTL的概念 函数send ...
- 36 网络相关函数(四)——live555源码阅读(四)网络
36 网络相关函数(四)——live555源码阅读(四)网络 36 网络相关函数(四)——live555源码阅读(四)网络 简介 7)createSocket创建socket方法 8)closeSoc ...
- 33 网络相关函数(一)——live555源码阅读(四)网络
33 网络相关函数(一)——live555源码阅读(四)网络 33 网络相关函数(一)——live555源码阅读(四)网络 简介 1)IsMulticastAddress多播(组播)地址判断函数 多播 ...
- gogs 源码阅读笔记 001
gogs 源码阅读笔记 001 gogs项目相当不错,本笔记实际是基于gogs fork版本 git-122a66f. gitea (gitea版本由来)[https://blog.gitea.io/ ...
随机推荐
- Vue中使用fullpage.js
Vue中使用fullpage.js:https://blog.csdn.net/weixin_34184158/article/details/88672739
- 关于eclipse设置JRebel
版本:eclipse ee Version: 2018-09 (4.9.0) jrebel:最新2019-2 1.在eclipse->help->eclipse Marketplace 2 ...
- VS Code Python 全新发布!Jupyter Notebook 原生支持终于来了!
VS Code Python 全新发布!Jupyter Notebook 原生支持终于来了! 北京时间 2019 年 10 月 9 日,微软发布了全新的 VS Code Python 插件,带来了众多 ...
- luoguP3261_[JLOI2015]城池攻占
题意 有一棵树\(n\)个节点,每个节点有一个防御值,以及两个属性,表示一个骑士占领该节点后攻击值是加还是乘,有\(m\)个骑士,有初始位置和初始攻击值,如果攻击值大于该节点的防御值,就能占领该节点, ...
- filebeat开启自带模块收集日志如何辨别日志来源等
filebeat启动自带模块后,日志先输出到Redis中 比如开启了system模块日志和redis模块日志 在Redis中查看收集过来的日志时,可以看到如下的这些信息 system日志信息 { &q ...
- docker安装教程-centos
Docker 要求CentOS 系统的内核版本在3.10以上,查看本页面的前提条件来验证你的CentOS 版本是否支持Docker . 1.通过uname -r 命令查看你当前的内核版本 uname ...
- springboot(十五)-Runner启动器
Runner启动器 如果你想在Spring Boot启动的时候运行一些特定的代码,你可以实现接口ApplicationRunner或者CommandLineRunner,这两个接口实现方式一样,它们都 ...
- 传输层协议之TCP/UDP
1.UDP UDP协议是面向无连接的,即不需要在正式传递数据前先链接双方,UDP协议只是数据报文的搬运工,不保证有序且不丢失的传递到对端,且UDP协议无任何控制流量的算法,UDP相对于TCP更加轻便. ...
- iphone手机软件安装目录
iPhone系统常用文件夹位置 1.[/Applications] 常用软件的安装目录 2. [/private /var/ mobile/Media /iphone video Recorder] ...
- 爬虫之request相关请求
一.解析json格式数据 (1) # (1)解析json 对象数据 # import requests # 返回的数据进行解析 # response = requests.get('http://ht ...