zoukankan      html  css  js  c++  java
  • 源码阅读-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

  • 相关阅读:
    冒泡排序
    tp框架---View视图层---模板继承(举例说明)
    tp框架---表单验证
    对thinkphp的命名空间的理解
    控制器操作方法的调用
    thinkphp的空控制器和空操作以及对应解决方法
    tp框架的url模式
    tp框架的MVC模式
    thinkphp目录结构
    Linux Centos 下安装软件 三种方式(转)
  • 原文地址:https://www.cnblogs.com/gaox97329498/p/12070063.html
Copyright © 2011-2022 走看看