iOS router 設計

iOS頁面之間的跳轉經常使用基於URL的router和mediator,過去有蘑菇街的方案 ([limboy.me/tech/2016/0…]) 和Casa Taloyum的方案 ([casatwy.com/iOS-Moduliz…]) 的激烈討論,業界的各類方案其實也是這兩種方案的變種,包括豆瓣的解決方案 ([github.com/douban/FRDI…]) 是基於URL註冊的擴展,吸納了Android的設計,解決了URL字符串不能傳遞對象的缺點。
我認爲一個好的頁面跳轉方案必須考慮到如下功能:html

頁面的解耦

不一樣頁面之間直接持有viewcontroller對象而後進行push顯然是很差的實踐,A頁面的改動會影響到持有它的B頁面的代碼,因此經過一箇中間者進行解耦是天然而然的設計。這個中間者能夠是一個mediator也能夠是一個協議名稱。
把頁面的class名字做爲協議名稱是bad case的設計,有時候會看到這樣的設計:git

+ (UIViewController *)getControllerWithName:(NSString *)vcClassString action:(NSString *)actionName passObject:(id)object {
             // return viewController;
  }複製代碼

之因此不是好的設計,是由於A頁面都感知B頁面的類名了,就破壞了解耦的意圖,若是B頁面想重命名,還須要通知各個引用到B頁面名字的人一一更名字。github

傳遞參數

A頁面打開B頁面,A頁面常常須要向B頁面傳遞參數,B頁面也有可能向A頁面回傳參數。參數必須支持原始數據類型、字符串還有不方便序列化的對象(如UIImage)。安全

遠程跳轉

支持遠程跳轉到指定的頁面是router必不可少的功能。因此router要有把url解析成相應頁面的能力。對於hybrid架構的H5頁面,router也要提供根據url跳轉到H5頁面的功能。架構

安全性

對於支付等涉及到安全性的頁面,不該該開放遠程跳轉的能力。因此router要區分出遠程調轉和本地跳轉,並且對於遠程跳轉的頁面要限制跳轉的目標頁面範圍。ui

多級頁面跳轉

提供跳轉到棧底的某個頁面的功能,由於交互和產品的需求,不少頁面並非直接pop出堆棧,而是用戶點擊後要跳轉到棧底的某個特定頁面,因此這時候就要求router不能僅僅提供pop的功能,而是須要利用中間者進行跳轉,而跳轉方案一樣要符合解耦的要求,不能直接引用class或者classname。url


過去的一年多經歷了幾個App,總結下實踐下來以爲work得還不錯的方案。spa

基於配置文件的頁面scheme

這是配置的頁面的scheme,scheme字段用於標識一個頁面,在內部跳轉到遠程跳轉都須要用到,統一了內部和外部的跳轉。needLogin表示這個頁面在push的時候須要驗證登陸,若是沒有登陸的話就自動喚起登陸頁面。allowRemote標識了這個頁面容許遠程跳轉。
對於外部跳轉,接口設計以下,url只須要傳入定義好協議的字符串便可。設計

[DRCRouter openURL:url];複製代碼

對於內部跳轉,接口設計以下,params傳入dictionary,支持非序列化的對象。code

[DRCRouter pushWithSchema:@"orderDetail" params:@{@"orderId":orderId}];複製代碼

其實外部跳轉只是內部跳轉的一個子集,對於經過openURL打開native頁面的狀況,最終也是通過解析調用pushWithSchema方法。

結合scheme的頁面回退

對於須要回退到棧底的某個頁面的時候,調用接口:

[DRCRouter popToSchema:@"orderDetail"];複製代碼

能夠調轉到棧底的任意頁面,原理也是經過配置表去查找scheme對應的vc。

前置攔截

爲了安全性的需求,有些頁面只能容許內部跳轉,外部跳轉即便拼對了url也不容許跳轉。因此router內部會根據來源來判斷是否能跳轉到相應的頁面。而且,對於須要登陸才能進入的頁面,會先彈出登陸框用戶登陸後再進入頁面。


未完待續。

相關文章
相關標籤/搜索