摘要:每個都定義了可以監聽它們的行為的接口如果需要支持多個設備和不同的展示方式,程序中會有其他類,沒有意大利面條的代碼。使用這樣的架構的好處是顯而易見的界面之間沒有依賴關系。更干凈的代碼,我看到的唯一意大利面條代碼是我做的。
引言
問題開發iOS應用時,現在更應該避免在一個視圖控制器中直接展示其他視圖控制器。
為什么?
現代應用程序通常需要需要支持以多種方式展示相同的視圖控制器。例如,在iPhone上你 push 一個新的視圖控制器,但是在 iPad 上,你會把它嵌入另一個視圖控制器或者用 popover 展示出來。
另外,很多情況下,你可能想在不同的情景中重用同一個視圖控制器。如 UIImagePickerController 可以在多個地方以不同的方式展示出來。
視圖控制器應該不依賴于他們的展示樣式,這就是 SizeClasses 出現的原因之一。
如果你從其他 VCs / ViewModels 展示視圖控制器,你將寫出來一堆if語句,你的代碼將變成條件大面條(big spaghetti of conditions)。
我作為一個顧問,經常需要參與審查項目,并幫助團隊制訂更干凈的解決方案。
我看到過很多的意大利面條代碼。下面這個就是相當糟糕的一個例子,但是還沒有接近我見過最差的:
func doneButtonTapped() { let vc = NextViewController(prepareNeccesaryState()) if Device.isIPad() { navigationController.pushViewController(vc, animated: true, completion: nil) } else { var nav = UINavigationController(rootViewController: vc) nav.modalPresentationStyle = UIModalPresentationStyle.Popover var popover = nav.popoverPresentationController popoverContent.preferredContentSize = CGSizeMake(500, 600) popover.delegate = self popover.sourceView = self.view popover.sourceRect = CGRectMake(100, 100, 0, 0) presentViewController(nav, animated: true, completion: nil) } }
這個幼稚的實現存在很多問題:
不必要的依賴 —— 一個視圖控制器不需要知道另一個
可重用性差
面條代碼,如果你的應用需要以不同的方式展示視圖 - 你需要寫大量的控制流。
單例是誘人的,因為它們讓你更容易編寫代碼。
測試更難,你的VC / VM會有很多的副作用。
我們怎樣才能解決這個問題? 清理你的 ViewControllers / ViewModels這可以應用到 MVVM,MVC 和許多其他的常見模式。當我談到 VC / VM,思考一下你現在正在使用的那一個。
讓我們使用代理或者基于 block 的接口,而不是對相關的控制器硬編碼,來擺脫所有的依賴關系。
class MyViewController { let onDone = (Void -> Void)? func doneButtonTapped() { onDone?(prepareNeccesaryState()) } }
ViewController / ViewModel 應該:
不能引用其他界面
不使用任何 UIKit presentation 類或類似 UINavigationController 或 presentViewController 的方法
有允許其他的對象通過注冊來獲知這個功能正在運行的接口,例如,代理或 block
不引用任何單例,稍后你會看到用我的做法是如何容易實現這一要求的。
這個時候,我們已經提高了可測試性,因為我們現在可以測試我們的接口是否被觸發了,且無需副作用。偽代碼:
let vc = createVC() var executed = false vc.onDone = { executed = true } //! add code here to trigger done state expect(executed).toEventually(beTruthy())
但是,我們如何協調我們的應用程序視圖控制器?
介紹 FlowControllers一個 FlowController 是一個簡單的對象,它將管理你的應用程序的一部分,我喜歡把它看成用例的一個子集。
FlowController 的三個主要角色是:
為視圖控制器配置特定上下文 - 例如分別為從應用 CreatePost 界面彈出的 ImagePicker 和改變用戶頭像時彈出的設置不同的配置
監聽每個 ViewController 中的重要事件,并用來協調它們之間的流程。
為視圖控制器提供它需要的東西,從而移除VC中的單例
func configureProgramsViewController(viewController: ProgramsViewController, navigationController: UINavigationController) { viewController.state = state viewController.addProgram = { [weak self] barButton in guard let strongSelf = self else { return } let createVC = R.storyboard.createProgram.initialViewController! strongSelf.configureCreateProgramViewController(createVC, navigationController: navigationController) navigationController.pushViewController(createVC, animated: true) } }
常見帶有 FlowControllers 的應用架構像這樣:
每個應用程序都有至少一個 FlowController,Root FlowController 由 AppDelegate 創建。
*實際上是 AppDelegate 中的一個 ApplicationController 創建了它,作為一個經驗法則,你永遠不應該引??用你的AppDelegate,永遠。*
每個 FlowController 可以有子控制器。
*如果您的應用程序具有可被看作是一個整體,需要多個屏幕的用戶故事的一些重要的子集(如創建新的鍛煉計劃),那么你可以為那一部分創建一個新的子控制器,并從主控制器展示它。*
VC / VM 不知道其他 VC / VM。
*這意味著他們可以在任何地方重復使用,如果一個步驟是從導入用戶照片庫里的東西,你可以在應用程序的不同部分重復使用這段代碼,例如,EditProfile可以使用相同的選擇器選擇用戶頭像。*
流量控制器配置和協調不同的界面。
每個 VC / VM 都定義了可以監聽它們的行為的接口
如果需要支持多個設備和不同的展示方式,程序中會有其他 FlowController 類,沒有意大利面條的代碼。
這個想法最初是 Jim 和 Sami 一年前介紹給我的,我們經常使用它。
盡管我們的應用劇烈改變了3次,我們的架構都輕松地應對了,我們能夠重復使用大量的代碼,也有不少控制器不需要任何改變。
使用這樣的架構的好處是顯而易見的:
界面之間沒有依賴關系。
高復用率。
更簡單的代碼注入并移除了單例。
更干凈的代碼,我看到的唯一意大利面條代碼是我做的。
以更有表現力的方式來導航。
能夠在共用大多數代碼時對不同的設備編寫不同的流。
可以輕松分離測試每個 VC / VM,因為一切都可以注入。沒有必要子類化。
現在,在一些架構中也有類似的概念,如 VIPER 有路由器。但它們通常是很復雜的,需要大量的前期成本,以適配到現有的應用程序中。
這個方法最棒的地方是它很簡單直觀,立刻就可以(在現有的項目中)使用它,無需等待新項目。它在小型和大型項目的效果一樣好。
不管你使用 MVVM,MVC 還是其他模式,如果應用中存在界面跳轉,不妨試一試。
原文作者:Krzysztof Zab?ocki
原文鏈接:http://merowing.info/2016/01/improve-your-ios-architecture-with-flowcontrollers/
翻譯自 MaxLeap 團隊_UX成員:Alex Sun
翻譯首發鏈接:https://blog.maxleap.cn/archives/879
商業轉載請聯系作者獲得授權,非商業轉載請注明作者信息與出處。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/11749.html
摘要:移動精英開發社群的第期,也是圍繞架構這個話題進行討論。本次我們希望結合實際開發中遇到的問題,來聊聊移動端的架構設計。這樣的模式改進一些,可能會更適合移動端架構。潘衛杰之前我們公司移動端的大項目就是插座式開發的,批量出各個行業的。 此前,58 同城的技術委員會執行主席沈劍在 OneAPM 的技術公開課上分享過一個主題,「好的架構不是設計出來的,而是演技出來的」。因為對很多創業公司而言,隨...
閱讀 712·2021-11-22 13:52
閱讀 1518·2021-09-27 13:36
閱讀 2818·2021-09-24 09:47
閱讀 2172·2021-09-22 15:48
閱讀 3600·2021-09-22 15:39
閱讀 1461·2019-08-30 12:43
閱讀 2918·2019-08-29 18:39
閱讀 3181·2019-08-29 12:51