- 背景
大型app的開發過程,伴隨著多個業務線的同時進行。上層業務之間不允許出現耦合,但是免不了業務頁面之間會相互跳轉。因此,引入間接的導航器,通過它,將頁面之間的依賴下沉,解除上層業務之間的耦合。
但是這樣,導航器注入了所有的依賴,在OC中,可以通過反射,用字符串匹配類,來解除這些依賴。可是對于Swift,由于個人水平有限,還沒有找到辦法解決這個問題。如果你有好的解決方案,謝謝你告訴我。
二 實現
雖然Swift版導航器,背離了解耦的初衷,但是它仍然是有存在意義的。導航器的用法,通過url來進行跳轉,可以避免直接依賴,免于寫重復代碼。像下面這樣,一句話能跳轉到對應的頁面:
Navigator.open(“hello”)
Swift動態能力的缺乏,使得通過url映射某個類,必須是顯示的把url和類進行注冊。于是有了下面這個方法,通過字典將url和類型保存起來。
func register(_ host: String, _ type: Any) {
urlMap[host] = type
}
在程序啟動時,調用register方法集中注冊:
Navigator.register("hello", MyController.self)
Navigator.register("world", YourController.self)
一般的做法,在調用導航器跳轉方法時,拿到類型后,會生成對應的頁面實例,根據參數push或者present。但是這樣,對頁面的約束較大,必須擁有統一的初始化方法,固定的參數等,而且這個導航器的作用就只能用來進行頁面跳轉了。我們換個思路,拿到類型后,要做的事,交給類自己,導航器只做一層類方法轉發調用,這樣就很靈活。于是,設計NBNavigatable協議,它的唯一方法是類被導航后要做的事,所需要的參數都從NBURL(NBURL是一個封裝的url對象)里取得,實現中你可以做任何事,push到界面上或者彈一個提示框,都可以:
protocol NBNavigatable {
static func opened(_ url: NBURL) -> Any?
}
能夠被導航的類,需要遵從這個協議:
extension MyController : NBNavigatable {
static func opened(_ url: NBURL) -> Any? {
let controller = MyController.self();
return controller
}
}
有了協議后,注冊方法需要做如下改動,只能注冊滿足協議的類型,而且保存類型的opened方法即可。
func register(_ host: String, _ type: NBNavigatable.Type) {
urlMap[host] = type.opened
}
跳轉方法,參數變成NBURL,將需要傳遞的參數都塞進去,被跳轉類可以通過 __func object(ForKey key: String) -> Any? __取到對應的值。
let url = NBURL("myapp://hello?title=world")
url.setObject("13100001111", forKey: "number")
Navigator.open(url)
這里的scheme需要在程序啟動時設置的,有效的scheme才使用導航器跳轉,外部的非法的scheme使用系統方法進行跳轉。
當然,導航器大部分作用還是頁面跳轉,于是寫了一個UIViewController的擴展,封裝了常見的頁面跳轉實現。
三 用法
總結一下使用過程:
1、程序啟動時,注冊url與類,并且設置有效scheme;
2、可以被跳轉的類遵從NBNavigatable協議,在opened方法里實現被跳轉時要做的事;
3、使用open方法跳轉。
源碼見這里 ,歡迎給我提意見。