前言
在APP開發過程中,必然會遇到在WebView和推送消息中打開其他頁面的需求,進一步則是在任何動態界面.
但隨著APP越來越大,功能模塊越來越復雜,采用傳統的控制器跳轉方式,需要持有跳轉對象,就會造成復雜的依賴鏈,代碼耦合性變強.
采用Routable的方式進行動態界面跳轉則不會有這個問題.
傳統跳轉:
ProjectDetailViewController* pro = [[ProjectDetailViewController alloc]init];
pro.StrID = @"XX";
pro.Memo = @"XX";
[self.navigationController pushViewController:pro animated:YES];
Routable跳轉:
[[Routable sharedRouter] open:@"ProjectDetail/XX/XX"];
Routable使用
1.注冊協議
//一般在APP入口didFinishLaunchingWithOptions中進行注冊
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//map規則 @"跳轉標識/:參數1/:參數2...."
[[Routable sharedRouter] setNavigationController:nav];
[[Routable sharedRouter] map:@"ProjectDetail/:StrID/:Memo/:Name" toController:[ProjectDetailViewController class]];
}
2.使用協議進行跳轉
//open規則 @"跳轉標識/參數1/參數2"
[[Routable sharedRouter] open:@"ProjectDetail/XX/XX"];
Routable代碼解析
關鍵方法:sharedRouter
map
open
setNavigationController
sharedRouter方法:
//使用dispatch_once初始化單例對象 保證一個程序生命周期中使用同一個Router對象
+ (instancetype)sharedRouter {
static Routable *_sharedRouter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedRouter = [[Routable alloc] init];
});
return _sharedRouter;
}
map方法:
- (void)map:(NSString *)format toController:(Class)controllerClass withOptions:(UPRouterOptions *)options {
if (!format) {
@throw [NSException exceptionWithName:@"RouteNotProvided"
reason:@"Route #format is not initialized"
userInfo:nil];
return;
}
if (!options) {
options = [UPRouterOptions routerOptions];
}
options.openClass = controllerClass;
//關鍵代碼 創建UPRouterOptions對象 將傳入的類對象作為value 參數字符串作為key存儲在可變字典
[self.routes setObject:options forKey:format];
}
setNavigationController方法:
//Router對象中有一個navigationController參數 用來保存傳入的導航視圖控制器 在open方法中會使用這個導航視圖控制器進行跳轉
@property (readwrite, nonatomic, strong) UINavigationController *navigationController;
open方法:
//調用Router類中的該方法 將傳入的參數格式化成RouterParams對象
//再通過RouterParams對象從self.routes中獲取對應的openClass類對象
//使用navigationController進行跳轉
- (void)open:(NSString *)url
animated:(BOOL)animated
extraParams:(NSDictionary *)extraParams
{
RouterParams *params = [self routerParamsForUrl:url extraParams: extraParams];
UPRouterOptions *options = params.routerOptions;
if (options.callback) {
RouterOpenCallback callback = options.callback;
callback([params controllerParams]);
return;
}
if (!self.navigationController) {
if (_ignoresExceptions) {
return;
}
@throw [NSException exceptionWithName:@"NavigationControllerNotProvided"
reason:@"Router#navigationController has not been set to a UINavigationController instance"
userInfo:nil];
}
UIViewController *controller = [self controllerForRouterParams:params];
if (self.navigationController.presentedViewController) {
[self.navigationController dismissViewControllerAnimated:animated completion:nil];
}
if ([options isModal]) {
if ([controller.class isSubclassOfClass:UINavigationController.class]) {
[self.navigationController presentViewController:controller
animated:animated
completion:nil];
}
else {
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
navigationController.modalPresentationStyle = controller.modalPresentationStyle;
navigationController.modalTransitionStyle = controller.modalTransitionStyle;
[self.navigationController presentViewController:navigationController
animated:animated
completion:nil];
}
}
else if (options.shouldOpenAsRootViewController) {
[self.navigationController setViewControllers:@[controller] animated:animated];
}
else {
[self.navigationController pushViewController:controller animated:animated];
}
}