最后更新: 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. springboot笔记-thymeleaf

    简介:Thymeleaf 是⾯向 Web 和独⽴环境的现代服务器端 Java 模板引擎,能够处理 HTML.XML.JavaScript.CSS 甚至纯文本.Thymeleaf 的作用域在 HTML ...

  2. ftp读取图片并转Base64

    public String download(String ftpUrl,String sfzh){ FTPClient ftpClient = new FTPClient(); InputStrea ...

  3. 弹出ifream

      top.$.jBox("iframe:"+'${ctx}/synopsis/hmlwxSynopsis/addItem', {title: "添加作品",w ...

  4. 移动端 h5 适配之必知必会

    建议大家先去看看这篇文章 https://juejin.im/post/5cddf289f265da038f77696c?utm_source=gold_browser_extension(来自掘金: ...

  5. OCR(光学字符识别)技术简介

    OCR技术起源 OCR最早的概念是由德国人Tausheck最先提出的,1966年他们发表了第一篇关于汉字识别的文章,采用了模板匹配法识别了1000个印刷体汉字.早在60.70年代,世界各国就开始有OC ...

  6. java实现spark常用算子之countbykey

    import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spa ...

  7. Input常用的输入框验证(正则)

    1.只是不能输入空格 <input type="text" οnkeyup="this.value=this.value.replace(/^ +| +$/g,'' ...

  8. 字符串的 Base64 加密和解密

    base64加密: FORM encode_base64 USING p_business “字符串string CHANGING p_base64. DATA l_xstring TYPE xstr ...

  9. EC元素

    '''判断title是否是一致,返回布尔值'''WebDriverWait(driver,10,0.1).until(EC.title_is("title_text")) '''判 ...

  10. Redis的频道发布与消息订阅

    Redis的频道发布与消息订阅 官网介绍 进程间的一种通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. 订阅/发布消息图 下图展示了频道channel1,以及订阅这个频道的三个客户端-c ...