今天来聊聊组件化,之前一直听说大厂在搞,什么淘宝架构,什么蘑菇街,既然谈到了架构的问题,那必属重中之重。接下来分析一下蘑菇街开源的代码,自己做个总结。

引入

类书本的文章个人感觉还是写不来的,再搬到自己写的东西这来也不合适,所以直接上一链接,通过链接文章大致可了解下它的前身后世,产生原因,以及整体宏观架构设计,而我接下来要做的是细化,以及转化,便于自己吸收 ———> 组件化架构漫谈

1. 话不多说,先看入口:

@interface MGJRouter ()
/***  保存了所有已注册的 URL*  结构类似 @{@"beauty": @{@":id": {@"_", [block copy]}}}*/
@property (nonatomic) NSMutableDictionary *routes;
@end+ (instancetype)sharedInstance
{static MGJRouter *instance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{instance = [[self alloc] init];});return instance;
}

很明显,蘑菇街架构(以下简称MGJ)通过该单例作管理,统一进行调配,而该单例仅有一个变量,就是routes,实际上它仅仅是管理了一个字典的结构,具体字典内有哪些内容,我们慢慢看;

2. 回调Block的定义
/***  routerParameters 里内置的几个参数会用到上面定义的 string*/
typedef void (^MGJRouterHandler)(NSDictionary *routerParameters);/***  需要返回一个 object,配合 objectForURL: 使用*/
typedef id (^MGJRouterObjectHandler)(NSDictionary *routerParameters);

上面这两个block定义是MGJ注册URL的回调,一个带返回值,另一个不带,在这里我们说一下带返回值的block用法;如下举例 ——>

//声明
typedef UIViewController *(^ViewControllerHandler)();//作参数
@interface DemoListViewController : UIViewController
+ (void)registerWithTitle:(NSString *)title handler:(ViewControllerHandler)handler;
@end//定义
@implementation DemoListViewController
+ (void)registerWithTitle:(NSString *)title handler:(ViewControllerHandler)handler
{UIViewController* vc = handler()
}
@end//在别处调用
@implementation DemoDetailViewController
[DemoListViewController registerWithTitle:@"基本使用" handler:^UIViewController *{return DemoDetailViewController();
}];
@end

如上,我们把ViewControllerHandler的运行延迟到了实际调用的时刻,并且我们可以在这个handler的实现中带入很多信息;

3. MGJ数据结构管理
extern NSString *const MGJRouterParameterURL;
extern NSString *const MGJRouterParameterCompletion;
extern NSString *const MGJRouterParameterUserInfo;
//*************************************************
static NSString * const MGJ_ROUTER_WILDCARD_CHARACTER = @"~";  //这是一个占位符
static NSString *specialCharacters = @"/?&.";NSString *const MGJRouterParameterURL = @"MGJRouterParameterURL";
NSString *const MGJRouterParameterCompletion = @"MGJRouterParameterCompletion";
NSString *const MGJRouterParameterUserInfo = @"MGJRouterParameterUserInfo";

从这里我们可以看出,MGJ的路由管理,实际上是一个解析url以及对应的管理,我们举几个URL来看一下:

@"mgj://"
@"mgj://foo/bar/none/exists"
@"mgj://foo/bar"
@"mgj://category/家居"
@"mgj://category/travel"
@"mgj://search/:query"
@"mgj://detail"
@"mgj://search/:keyword"
@"mgj://search_top_bar"

通过上面的URL我们可以看出,路由的管理实际上就是url的解析过程,下面我们来具体看一下解析过程;

4. URL解析
  • route url

- (NSArray*)pathComponentsFromURL:(NSString*)URL
{NSMutableArray *pathComponents = [NSMutableArray array];if ([URL rangeOfString:@"://"].location != NSNotFound) {NSArray *pathSegments = [URL componentsSeparatedByString:@"://"];// 如果 URL 包含协议,那么把协议作为第一个元素放进去[pathComponents addObject:pathSegments[0]];// 如果只有协议,那么放一个占位符URL = pathSegments.lastObject;if (!URL.length) {[pathComponents addObject:MGJ_ROUTER_WILDCARD_CHARACTER];}}for (NSString *pathComponent in [[NSURL URLWithString:URL] pathComponents]) {if ([pathComponent isEqualToString:@"/"]) continue;if ([[pathComponent substringToIndex:1] isEqualToString:@"?"]) break;[pathComponents addObject:pathComponent];}return [pathComponents copy];
}
  • key-value
- (NSMutableDictionary *)addURLPattern:(NSString *)URLPattern
{NSArray *pathComponents = [self pathComponentsFromURL:URLPattern];NSMutableDictionary* subRoutes = self.routes;for (NSString* pathComponent in pathComponents) {if (![subRoutes objectForKey:pathComponent]) {subRoutes[pathComponent] = [[NSMutableDictionary alloc] init];}subRoutes = subRoutes[pathComponent];}return subRoutes;
}
  • 核心url解析

- (NSMutableDictionary *)extractParametersFromURL:(NSString *)url
{NSMutableDictionary* parameters = [NSMutableDictionary dictionary];parameters[MGJRouterParameterURL] = url;NSMutableDictionary* subRoutes = self.routes;NSArray* pathComponents = [self pathComponentsFromURL:url];BOOL found = NO;// borrowed from HHRouter(https://github.com/Huohua/HHRouter)for (NSString* pathComponent in pathComponents) {// 对 key 进行排序,这样可以把 ~ 放到最后NSArray *subRoutesKeys =[subRoutes.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {return [obj1 compare:obj2];}];for (NSString* key in subRoutesKeys) {if ([key isEqualToString:pathComponent] || [key isEqualToString:MGJ_ROUTER_WILDCARD_CHARACTER]) {found = YES;subRoutes = subRoutes[key];break;} else if ([key hasPrefix:@":"]) {found = YES;subRoutes = subRoutes[key];NSString *newKey = [key substringFromIndex:1];NSString *newPathComponent = pathComponent;// 再做一下特殊处理,比如 :id.html -> :idif ([self.class checkIfContainsSpecialCharacter:key]) {NSCharacterSet *specialCharacterSet = [NSCharacterSet characterSetWithCharactersInString:specialCharacters];NSRange range = [key rangeOfCharacterFromSet:specialCharacterSet];if (range.location != NSNotFound) {// 把 pathComponent 后面的部分也去掉newKey = [newKey substringToIndex:range.location - 1];NSString *suffixToStrip = [key substringFromIndex:range.location];newPathComponent = [newPathComponent stringByReplacingOccurrencesOfString:suffixToStrip withString:@""];}}parameters[newKey] = newPathComponent;break;}}// 如果没有找到该 pathComponent 对应的 handler,则以上一层的 handler 作为 fallbackif (!found && !subRoutes[@"_"]) {return nil;}}// Extract Params From Query.NSArray<NSURLQueryItem *> *queryItems = [[NSURLComponents alloc] initWithURL:[[NSURL alloc] initWithString:url] resolvingAgainstBaseURL:false].queryItems;for (NSURLQueryItem *item in queryItems) {parameters[item.name] = item.value;}if (subRoutes[@"_"]) {parameters[@"block"] = [subRoutes[@"_"] copy];}return parameters;
}
+ (void)openURL:(NSString *)URL withUserInfo:(NSDictionary *)userInfo completion:(void (^)(id result))completion
{URL = [URL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];NSMutableDictionary *parameters = [[self sharedInstance] extractParametersFromURL:URL];[parameters enumerateKeysAndObjectsUsingBlock:^(id key, NSString *obj, BOOL *stop) {if ([obj isKindOfClass:[NSString class]]) {parameters[key] = [obj stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];}}];if (parameters) {MGJRouterHandler handler = parameters[@"block"];if (completion) {parameters[MGJRouterParameterCompletion] = completion;}if (userInfo) {parameters[MGJRouterParameterUserInfo] = userInfo;}//所以注册路由时的回调是在这里才调用到的//也就是openURL响应了register的回调if (handler) {[parameters removeObjectForKey:@"block"];handler(parameters);}}
}

MGJRouter代码分析相关推荐

  1. 20145236《网络攻防》Exp4 恶意代码分析

    20145236<网络攻防>Exp4 恶意代码分析 一.基础问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些 ...

  2. C#中类的继承 override virtual new的作用以及代码分析

    继承中override virtual new的作用 virtual 父类中需要注明允许重写的方法: override 子类中必须显示声明该方法是重写的父类中的方法: new 子类中忽略父类的已存在的 ...

  3. 2017.4.18 静态代码分析工具sonarqube+sonar-runner的安装配置及使用

    配置成功后的代码分析页面: 可以看到对复杂度.语法使用.重复度等等都做了分析,具体到了每一个方法和每一句代码. 四种使用方式: sonarqube + sonar-runner sonarqube + ...

  4. lighttpd1.4.18代码分析

    lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态 posted @ 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1)  编辑 lig ...

  5. Device Tree(三):代码分析

    2019独角兽企业重金招聘Python工程师标准>>> 一.前言 Device Tree总共有三篇,分别是: 1.为何要引入Device Tree,这个机制是用来解决什么问题的?(请 ...

  6. 使用Hadoop和ELK进行业务代码分析!分分钟捉到Bug!

    大数据是计算领域的新高地,它有望提供一种方法来应对二十一世纪不断增长的数据生成.越来越多的大数据爱好者正在涌现,越来越多的公司正在采用各种大数据平台,并希望提出以客户为中心的解决方案,帮助他们在竞争激 ...

  7. 20145328 《网络对抗技术》恶意代码分析

    20145328 <网络对抗技术>恶意代码分析 ------看到这句话说明还没写完-------- 实践内容: 使用schtasks指令监控系统运行 使用sysmon工具监控系统运行 使用 ...

  8. starGAN原理代码分析

    下载: git clone https://github.com/yunjey/StarGAN.git 1 cd StarGAN/ 1 下载celebA训练数据: bash download.sh 1 ...

  9. tensorflow笔记:多层CNN代码分析

    tensorflow笔记系列:  (一) tensorflow笔记:流程,概念和简单代码注释  (二) tensorflow笔记:多层CNN代码分析  (三) tensorflow笔记:多层LSTM代 ...

  10. ARM裸机篇---启动代码分析

    ARM裸机篇---启动代码分析 先搞清楚启动代码和Bootloader的区别,启动代码是指CPU复位后到进入C语言的main函数之前需要执行的那段汇编代码. 下面的代码先暂且这样吧,没啥注释的,时间关 ...

最新文章

  1. docker mysql详解_Docker轻松入门(详解)
  2. 【Python】SyntaxError: unexpected EOF while parsing
  3. css实现自适应背景图及背景图透明度处理
  4. python中文读音ndarray-numpy中的ndarray方法和属性详解
  5. java 等待唤醒机制,Java线程等待唤醒机制
  6. mysql基本表管理sql语句
  7. 【Kafka】Kafka 配置 SCRAM认证
  8. {转}Java 字符串分割三种方法
  9. WPF和Expression Blend开发实例:Adorner(装饰器)应用实例
  10. 修复easyMule for Mac 2.0崩溃造成的任务丢失
  11. CAD迷你看图2019破解版|CAD迷你看图2019R5中文破解版下载
  12. 我转行程序员的那一年(四)
  13. 计算理论导引重点知识回顾
  14. Mac安装虚拟机详细步骤
  15. ASO优化之新人必备的基础知识技能
  16. 自动合并两个.bib 去除.bib中的重复条目
  17. reflector 插件_Reflector Plus Plus-插件,IronPython和其他Peli Goodness
  18. 杜国光博士,基于视觉的机器人抓取--物体定位,位姿估计到抓取估计课堂笔记
  19. Windows服务优化(整理篇)
  20. JAVA计算平方,幂运算,三角函数等

热门文章

  1. Python基础之模块(Module)和包(Package)
  2. Java机器人解密游戏_解谜类游戏 篇十:在机器人的世界中,那些隐藏在谜题之下的眼泪...
  3. keyshot渲染玻璃打光_KeyShot渲染,打光这么打,效果倍儿棒!
  4. 关于搞国外广告联盟的一些思路
  5. 地图编辑器到底是做什么的?今天之后你会对此有个新的了解
  6. python箱形图各部分含义_箱形图以及python实践
  7. [模电]差模信号、共模信号的通俗解释
  8. 新高考十二种选科情况下,再选科目的考室安排的探索2.0版
  9. pantompkins matlab,Matlab对Python的findpeaks算法
  10. excel几个表合成一张_【一分钟Excel】如何快速合并多个工作表