• 源码阅读-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

    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

  • 相关阅读:
    JS身份证真实性校验(一)
    Python之文件操作
    python之数据类型
    Python之循环条件、变量、字符串格式化
    webpack之proxyTable设置跨域
    vue报错解决方案
    CentOS 7 下Ansiable搭建命令列表 及常用监控指令
    CentOS 7 下nagios搭建记录
    弹窗鼠标拖动功能-js
    做好探索性测试,体现你的价值
  • 原文地址:https://www.cnblogs.com/gaox97329498/p/12070063.html
Copyright © 2020-2023  润新知