源码阅读-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/ ...
随机推荐
- FTP服务器的搭建(CentOS 7)
注意ip地址为: 虚拟机ip设置 TYPE="Ethernet"BOOTPROTO="static"NAME="enp0s3"DEVICE= ...
- Anaconda折腾记(1)
Anaconda折腾记 谨此记录小白的我在Anaconda里面的摸爬滚打 更换更新源 可以不使用命令,直接进入C盘,进入user文件夹,进入当前的用户文件夹下,记得显示隐藏文件. 找到.condarc ...
- E - 秋实大哥与战争
秋实大哥与战争 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit S ...
- Exchange 2010 详细安装步骤
工具/原料 系统要求:windows 2008 R2 标准版或者企业版 Exchange Server 2010 SP3:https://www.microsoft.com/en-us/downl ...
- hadoop批量命令脚本xrsync.sh传输脚本
1.xrsync.sh脚本 #!/bin/bash if [[ $# -lt 1 ]] ; then echo no params ; exit ; fi p=$1 #echo p=$p dir=`d ...
- join 与 countdownlatch 的区别 扩展 栅栏 CyclicBarrier
我们先看一个 小例子 , 使用 join 与CountDownSlatch 都可以完成 当1,2线程 完全结束后 3 线程 start 对比我们就能够知道 CountDownSlatch 比 JOIN ...
- iOS 10 下 Plus 启动APP 导致Icon 铺满全屏问题
1.解决方法,添加LacuchScreen 启动图需要手动适配 http://stackoverflow.com/questions/39571694/ipad-application-shows-a ...
- Shiro多Realm验证
在单Realm的基础上,进行如下内容的修改 原有的ShiroRealm.java: package com.atguigu.shiro.realms; import org.apache.shiro. ...
- php通过反射方法调用私有方法
PHP 5 具有完整的反射 API,添加了对类.接口.函数.方法和扩展进行反向工程的能力. 下面我们演示一下如何通过反射,来调用执行一个类中的私有方法: <?php //MyClass这个类中包 ...
- python语音提示
#coding:utf8 import win32com.client speaker = win32com.client.Dispatch("SAPI.SpVoice") whi ...