蘑菇街组件化笔记

0.12字数 987阅读 145
路由的基础知识

iOS 系统里面支持的URL Scheme方式,我们可以看出,对于一个资源的访问,苹果也是用URI的方式来访问的。
统一资源标识符(英语:Uniform Resource Identifier,或URI)是一个用于标识某一互联网资源名称的字符串。 该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互操作。URI的最常见的形式是统一资源定位符(URL)。

1488337532106663.png

路由开源的库:
http://www.cocoachina.com/ios/20170301/18811.html (参考如下的文章)

组件之间的通信

URL路由的方式

注册:MGJRouter

各个组件初始化时向 Mediator 注册对外提供的接口,Mediator 通过保存在内存的表去知道有哪些模块哪些接口,接口的形式是 URL->block。

这种方案思路就是:Mediator 不能直接去调用组件的方法,因为这样会产生依赖,那我就要通过其他方法去调用,也就是通过 字符串->方法 的映射去调用。runtime 接口的 className + selectorName -> IMP 是一种,注册表的 key -> block 是一种,而前一种是 OC 自带的特性,后一种需要内存维持一份注册表。

从数据结构来看

@interface MGJRouter ()
/**
 *  保存了所有已注册的 URL
 *  结构类似 @{@"beauty": @{@":id": {@"_", [block copy]}}}
 */
@property (nonatomic) NSMutableDictionary *routes;
@end
/**
 *  打开此 URL,带上附加信息,同时当操作完成时,执行额外的代码
 *
 *  @param URL        带 Scheme 的 URL,如 mgj://beauty/4
 *  @param userInfo 附加参数
 *  @param completion URL 处理完成后的 callback,完成的判定跟具体的业务相关
 */
+ (void)openURL:(NSString *)URL withUserInfo:(NSDictionary *)userInfo completion:(void (^)(id result))completion;
1488345388154476.png
蘑菇街为了区分开页面间调用和组件间调用,于是想出了一种新的方法。用Protocol的方法来进行组件间的调用。

每个组件之间都有一个 Entry,这个 Entry,主要做了三件事:

  • 注册这个组件关心的 URL

  • 注册这个组件能够被调用的方法/属性

  • 在 App 生命周期的不同阶段做不同的响应

页面间的openURL调用就是如下的样

1488345427296974.png

每个组件间都会向MGJRouter注册,组件间相互调用或者是其他的App都可以通过openURL:方法打开一个界面或者调用一个组件。

在组件间的调用,蘑菇街采用了Protocol的方式。

1488345587646575.png

[ModuleManager registerClass:ClassA forProtocol:ProtocolA] 的结果就是在 MM 内部维护的 dict 里新加了一个映射关系。

[ModuleManager classForProtocol:ProtocolA] 的返回结果就是之前在 MM 内部 dict 里 protocol 对应的 class,使用方不需要关心这个 class 是个什么东东,反正实现了 ProtocolA 协议,拿来用就行。

这里需要有一个公共的地方来容纳这些 public protocl,也就是图中的 PublicProtocl.h。

我猜测,大概实现可能是下面的样子:

[图片上传中...(1488350374526176.png-ba68e1-1530103740148-0)]

然后这个是一个单例,在里面注册各个协议:


[图片上传中...(1488350511106764.png-9f1356-1530103814895-0)]

在ModuleProtocolManager中用一个字典保存每个注册的protocol。现在再来猜猜ModuleEntry的实现


1488350511106764.png

然后每个模块内都有一个和暴露到外面的协议相连接的“接头”。


1488346149928315 (1).png

在它的实现中,需要引入3个外部文件,一个是ModuleProtocolManager,一个是DetailModuleEntryProtocol,最后一个是所在模块需要跳转或者调用的组件或者页面。

1488346189157631.png

至此基于Protocol的方案就完成了。如果需要调用某个组件或者跳转某个页面,只要先从ModuleProtocolManager的字典里面根据对应的ModuleEntryProtocol找到对应的DetailModuleEntry,找到了DetailModuleEntry就是找到了组件或者页面的“入口”了。再把参数传进去即可。

1488346213448859.png

这样就可以调用到组件或者界面了。

如果组件之间有相同的接口,那么还可以进一步的把这些接口都抽离出来。这些抽离出来的接口变成“元接口”,它们是可以足够支撑起整个组件一层的。

推荐阅读更多精彩内容