组件化之 URL Route
iOS 中主要有三种组件化方式,URL Route、target-action、protocol 匹配。这里主要讲第一种:URL Route。
这类方式大致的思想是通过注册,根据不同 url 结构存入不同的 block。等待调用时,通过存储的 block 中返回对象或执行操作。没有利用 Runtime,相对来说实现比较简单。
优缺点
优点
实现简单。
缺点
- 依赖于命名规定,无法在编译时发现问题
- 通过硬编码的字符串来做解耦,某种意义上来说也是一种伪解耦,并没有做到真正的解耦。
代码实例
1 | // 注册某个URL |
1 | // 调用路由 |
MGJRouter 的实现
MGJRouter 是一个全局的单利对象,拥有以下方法:
1 | /** |
注册(Register)
注册的方法主要有两个+ (void)registerURLPattern:(NSString *)URLPattern toHandler:(MGJRouterHandler)handler;
和+ (void)registerURLPattern:(NSString *)URLPattern toObjectHandler:(MGJRouterObjectHandler)handler;
。
主要的区别在于 block 中是否返回对象。
底层实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30- (void)addURLPattern:(NSString *)URLPattern andHandler:(MGJRouterHandler)handler
{
NSMutableDictionary *subRoutes = [self addURLPattern:URLPattern];
if (handler && subRoutes) {
subRoutes[@"_"] = [handler copy];
}
}
- (void)addURLPattern:(NSString *)URLPattern andObjectHandler:(MGJRouterObjectHandler)handler
{
NSMutableDictionary *subRoutes = [self addURLPattern:URLPattern];
if (handler && subRoutes) {
subRoutes[@"_"] = [handler copy];
}
}
- (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;
}
通过pathComponentsFromURL
方法,将 URL 进行拆分。例如将mgj://foo/bar
=>mgj, foo, bar
。并通过循环将 URL 进行分层。
此时routes
的内容为:1
2
3
4
5
6
7
8{
mgj = {
foo = {
bar = {
};
};
};
}
并返回最内层的字典的指针,并在外部将 block 进行赋值。赋值后的内容为:1
2
3
4
5
6
7
8
9{
mgj = {
foo = {
bar = {
"_" = "<__NSMallocBlock__: 0x600002b88b10>";
};
};
};
}
至此成功将 Block 对象存入单利对象中的字典内,注册的流程到此结束。
执行(open)
open 的方法以下三个:
\+ (**void**)openURL:(NSString *)URL;
\+ (**void**)openURL:(NSString *)URL completion:(**void** (^)(**id** result))completion;
\+ (**void**)openURL:(NSString *)URL withUserInfo:(NSDictionary *)userInfo completion:(**void** (^)(**id** result))completion;
三者的区别主要是是否带参数,是否有完成的回调。
内部实现都为同一个方法:
1 | + (void)openURL:(NSString *)URL withUserInfo:(NSDictionary *)userInfo completion:(void (^)(id result))completion |
URL:mgj://foo/bar
进入方法,利用- (NSMutableDictionary *)extractParametersFromURL:(NSString *)url matchExactly:(**BOOL**)exactly
方法根据URL
从routes
中取出对应的block
。
此时parameters
中的内容为:
1 | { |
其中stringByAddingPercentEscapesUsingEncoding
和stringByReplacingPercentEscapesUsingEncoding
两个方法主要用于解决编码问题。
最后将completion
和userInfo
都存入parameters
中一并当作参数执行对应的block
。
到此根据 URL 执行的流程结束。