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