前言:
iOS強(qiáng)調(diào)模塊化、組件化,講究模塊內(nèi)高內(nèi)聚,模塊間低耦合。
那么模塊與模塊之間的低耦合,就要求模塊間的通信要盡可能的減少依賴,SDRouter,就是這樣的中間產(chǎn)物。
SDRouter的設(shè)計(jì)是參照一水流年的想法來實(shí)現(xiàn)的,總體和他的想法保持一致,但是會(huì)更加的簡(jiǎn)潔、易用,作者設(shè)計(jì)的拓展性強(qiáng),但是依賴過多,導(dǎo)致庫不太容易單獨(dú)存在。那么,你可以看到使用該庫,可以使用URL的方式打開任何Native頁面,如下面一個(gè)偽協(xié)議:asone://oneController?title=as_one
asone
是AppSchema.完全按照http協(xié)議涉及的跳轉(zhuǎn),讓該庫SDRouter的結(jié)構(gòu)簡(jiǎn)單,想法也簡(jiǎn)單。
先設(shè)想一下:如何從AController以URL的方式跳轉(zhuǎn)到BController并攜帶參數(shù)?
先看下SDRouter中是怎么實(shí)現(xiàn)的:
- (void)viewDidLoad {
[super viewDidLoad];
// 在頁面上添加一個(gè)button
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 100, 80)];
[button setTitle:@"one" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(go) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
// 點(diǎn)擊跳轉(zhuǎn)到下一個(gè)控制器 并攜帶下一個(gè)控制器的標(biāo)題
- (void)go {
NSDictionary *param = @{@"title":@"as_one"};
NSURL *url = SDURLRouteQueryLink(OneController, param);
[[SDRouter shareRutor] rutor:url];
}
再設(shè)想一下:如何從BController以O(shè)penUrl的方式打開CController并傳遞參數(shù)?
// 先忽略+load方法中的內(nèi)容
+ (void)load {
[[SDRouter shareRutor] addPaten:OneController callback:^(SDRouterContext *context) {
NSLog(@"優(yōu)品財(cái)富: %@",context.paramters);
OneViewController *textOneVc = [[OneViewController alloc] init];
textOneVc.navigationItem.title = context.paramters[@"title"];
[context.topNavigationController pushViewController:textOneVc animated:YES];
}];
}
// 先看這里
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0) green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0) alpha:1.0];
// 頁面上添加一個(gè)按鈕
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 100, 80)];
[button setTitle:@"openUrl" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(openUrl) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
// 點(diǎn)擊調(diào)轉(zhuǎn),以openUrl的方式打開一個(gè)控制器并攜帶參數(shù),該參數(shù)是navigationTitle。
- (void)openUrl {
NSDictionary *dict = @{@"title":@"as_two"};
NSURL *url = SDURLRouteQueryLink(TwoController, dict);
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {}];
}
最后再想一下,H5怎么快捷的打開CController并攜帶參數(shù)?
// H5頁面添加一個(gè)按鈕并添加js跳轉(zhuǎn)
<input class="class1 class2" type="button" value="跳轉(zhuǎn)到as_Three頁面" style="width:500px;height:150px;font-size:40px"onclick=javascrtpt:jump()>
function jump(){
window.location="asone://threeController?title=as??three";
}
上面三種設(shè)想可以參看下圖:
SDRouter設(shè)計(jì)思想:
- URL部分:看似URL跳轉(zhuǎn),實(shí)際上是對(duì)URL的解析、組合編解碼。
SDRouterUtil主要包含了對(duì)URL的解析及組合編解碼的方法。
@interface NSString (SDURLEncode)
- (NSString *)URLEncode;
- (NSString *)URLDecode;
@end
// 用來處理參數(shù)攜帶 拼接參數(shù) 返回編碼、拼接后的URL
FOUNDATION_EXTERN NSURL *SDURLRouteQueryLink(NSString *baseUrl, NSDictionary *query);
// 添加參數(shù)
FOUNDATION_EXTERN NSString *SDURLRouteJoinParamterString(NSString *urlStr, NSString *query);
// 將拼接好的參數(shù)encode
FOUNDATION_EXTERN NSString *SDURLRouteEncodeURLQueryParamters(NSDictionary *paramter);
// 將參數(shù)decode
FOUNDATION_EXTERN NSDictionary *SDURLRouteDecodeURLQueryParamters(NSString *urlStr);
- 跳轉(zhuǎn):
URL拼接好,從AController跳轉(zhuǎn)到BController,跳轉(zhuǎn)的方法其實(shí)很簡(jiǎn)單。
[[SDRouter shareRutor] rutor:url];
那這句代碼又做了什么呢?重點(diǎn)看這段代碼
+ (void)load {
[[SDRouter shareRutor] addPaten:OneController callback:^(SDRouterContext *context) {
NSLog(@"優(yōu)品財(cái)富: %@",context.paramters);
OneViewController *textOneVc = [[OneViewController alloc] init];
textOneVc.navigationItem.title = context.paramters[@"title"];
[context.topNavigationController pushViewController:textOneVc animated:YES];
}];
}
在SDRouter中提供了一個(gè)注冊(cè)的方法,必須在load方法中注冊(cè),+load是已知的執(zhí)行最早的方法,比main函數(shù)好要早,這里不做過多解釋,不明白可以參看你真的了解+load方法嗎?
addPaten:OneController
其實(shí)這個(gè)oneController是定義的字符串常量,如:asone://oneController?title=as_one,在App啟動(dòng)后,SDRouter會(huì)記錄當(dāng)前這個(gè)控制器和所攜帶的callback
。
// 實(shí)現(xiàn)比較簡(jiǎn)單
- (void)addPaten:(NSString *)paten callback:(SDCompleteCallback)callback{
NSDictionary *dict = @{paten:callback};
if (![_results containsObject:dict]) {
[_results addObject:dict];
}
}
在調(diào)用[[SDRouter shareRutor] rutor:url]
的時(shí)候,會(huì)匹配需要前往的url。
- (void)rutor:(NSURL *)paten {
SDURLParser *parser = [[SDURLParser alloc] initWithURL:paten];
[_results enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([[obj allKeys].firstObject isEqualToString:parser.paten]) {
SDRouterContext *context = [[SDRouterContext alloc] init];
context.paramters = parser.paramters;
if ([obj allValues].firstObject) {
SDCompleteCallback callback = (SDCompleteCallback)[obj allValues].firstObject;
callback(context);
}
*stop = YES;
}
}];
}
push
到這里,已經(jīng)能夠保證在+load方法中獲取到參數(shù),重點(diǎn)是頁面怎么push出來。因?yàn)?load方法執(zhí)行時(shí),是不能夠獲取到navigationController的,那么怎么獲取到并push呢?全局UI棧
其實(shí)一開始并沒有該類,但是通過其他方式獲取總是覺的雞肋,還是通過一水文章的點(diǎn)撥才有了該類。
該類中利用runtime方法替換,重寫Controller的生命周期方法,聲明一個(gè)指針數(shù)組,在viewWillApear的時(shí)候加入U(xiǎn)I棧,在disWill的時(shí)候移除UI棧,參數(shù)的攜帶和棧頂控制器的攜帶,是通過SDContext來完成的。該類中包含了參數(shù)及navigation。
講解比較粗略,想了解的可以到demo中查看。
github