成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

使用 FLOWCONTROLLERS 改進(jìn)IOS應(yīng)用架構(gòu)

wmui / 3291人閱讀

摘要:每個(gè)都定義了可以監(jiān)聽它們的行為的接口如果需要支持多個(gè)設(shè)備和不同的展示方式,程序中會(huì)有其他類,沒有意大利面條的代碼。使用這樣的架構(gòu)的好處是顯而易見的界面之間沒有依賴關(guān)系。更干凈的代碼,我看到的唯一意大利面條代碼是我做的。

引言

開發(fā)iOS應(yīng)用時(shí),現(xiàn)在更應(yīng)該避免在一個(gè)視圖控制器中直接展示其他視圖控制器。

為什么?

問題

現(xiàn)代應(yīng)用程序通常需要需要支持以多種方式展示相同的視圖控制器。例如,在iPhone上你 push 一個(gè)新的視圖控制器,但是在 iPad 上,你會(huì)把它嵌入另一個(gè)視圖控制器或者用 popover 展示出來。

另外,很多情況下,你可能想在不同的情景中重用同一個(gè)視圖控制器。如 UIImagePickerController 可以在多個(gè)地方以不同的方式展示出來。

視圖控制器應(yīng)該不依賴于他們的展示樣式,這就是 SizeClasses 出現(xiàn)的原因之一。

如果你從其他 VCs / ViewModels 展示視圖控制器,你將寫出來一堆if語句,你的代碼將變成條件大面條(big spaghetti of conditions)

我作為一個(gè)顧問,經(jīng)常需要參與審查項(xiàng)目,并幫助團(tuán)隊(duì)制訂更干凈的解決方案。

我看到過很多的意大利面條代碼。下面這個(gè)就是相當(dāng)糟糕的一個(gè)例子,但是還沒有接近我見過最差的:

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)
  }
}

這個(gè)幼稚的實(shí)現(xiàn)存在很多問題:

不必要的依賴 —— 一個(gè)視圖控制器不需要知道另一個(gè)

可重用性差

面條代碼,如果你的應(yīng)用需要以不同的方式展示視圖 - 你需要寫大量的控制流。

單例是誘人的,因?yàn)樗鼈冏屇愀菀拙帉懘a。

測(cè)試更難,你的VC / VM會(huì)有很多的副作用。

我們?cè)鯓硬拍芙鉀Q這個(gè)問題? 清理你的 ViewControllers / ViewModels

這可以應(yīng)用到 MVVM,MVC 和許多其他的常見模式。當(dāng)我談到 VC / VM,思考一下你現(xiàn)在正在使用的那一個(gè)。

讓我們使用代理或者基于 block 的接口,而不是對(duì)相關(guān)的控制器硬編碼,來擺脫所有的依賴關(guān)系。

class MyViewController {
  let onDone = (Void -> Void)?

  func doneButtonTapped() {
    onDone?(prepareNeccesaryState())
  }

}

ViewController / ViewModel 應(yīng)該:

不能引用其他界面

不使用任何 UIKit presentation 類或類似 UINavigationController 或 presentViewController 的方法

有允許其他的對(duì)象通過注冊(cè)來獲知這個(gè)功能正在運(yùn)行的接口,例如,代理或 block

不引用任何單例,稍后你會(huì)看到用我的做法是如何容易實(shí)現(xiàn)這一要求的。

這個(gè)時(shí)候,我們已經(jīng)提高了可測(cè)試性,因?yàn)槲覀儸F(xiàn)在可以測(cè)試我們的接口是否被觸發(fā)了,且無需副作用。偽代碼:

let vc = createVC()
var executed = false
vc.onDone = {
  executed = true
}
//! add code here to trigger done state
expect(executed).toEventually(beTruthy())

但是,我們?nèi)绾螀f(xié)調(diào)我們的應(yīng)用程序視圖控制器?

介紹 FlowControllers

一個(gè) FlowController 是一個(gè)簡單的對(duì)象,它將管理你的應(yīng)用程序的一部分,我喜歡把它看成用例的一個(gè)子集。

FlowController 的三個(gè)主要角色是:

為視圖控制器配置特定上下文 - 例如分別為從應(yīng)用 CreatePost 界面彈出的 ImagePicker 和改變用戶頭像時(shí)彈出的設(shè)置不同的配置

監(jiān)聽每個(gè) ViewController 中的重要事件,并用來協(xié)調(diào)它們之間的流程。

為視圖控制器提供它需要的東西,從而移除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 的應(yīng)用架構(gòu)像這樣:

每個(gè)應(yīng)用程序都有至少一個(gè) FlowController,Root FlowController 由 AppDelegate 創(chuàng)建。

*實(shí)際上是 AppDelegate 中的一個(gè) ApplicationController 創(chuàng)建了它,作為一個(gè)經(jīng)驗(yàn)法則,你永遠(yuǎn)不應(yīng)該引??用你的AppDelegate,永遠(yuǎn)。*

每個(gè) FlowController 可以有子控制器。

*如果您的應(yīng)用程序具有可被看作是一個(gè)整體,需要多個(gè)屏幕的用戶故事的一些重要的子集(如創(chuàng)建新的鍛煉計(jì)劃),那么你可以為那一部分創(chuàng)建一個(gè)新的子控制器,并從主控制器展示它。*

VC / VM 不知道其他 VC / VM。

*這意味著他們可以在任何地方重復(fù)使用,如果一個(gè)步驟是從導(dǎo)入用戶照片庫里的東西,你可以在應(yīng)用程序的不同部分重復(fù)使用這段代碼,例如,EditProfile可以使用相同的選擇器選擇用戶頭像。*

流量控制器配置和協(xié)調(diào)不同的界面。

每個(gè) VC / VM 都定義了可以監(jiān)聽它們的行為的接口

如果需要支持多個(gè)設(shè)備和不同的展示方式,程序中會(huì)有其他 FlowController 類,沒有意大利面條的代碼。

這個(gè)想法最初是 Jim 和 Sami 一年前介紹給我的,我們經(jīng)常使用它。

盡管我們的應(yīng)用劇烈改變了3次,我們的架構(gòu)都輕松地應(yīng)對(duì)了,我們能夠重復(fù)使用大量的代碼,也有不少控制器不需要任何改變。

使用這樣的架構(gòu)的好處是顯而易見的:

界面之間沒有依賴關(guān)系。

高復(fù)用率。

更簡單的代碼注入并移除了單例。

更干凈的代碼,我看到的唯一意大利面條代碼是我做的。

以更有表現(xiàn)力的方式來導(dǎo)航。

能夠在共用大多數(shù)代碼時(shí)對(duì)不同的設(shè)備編寫不同的流。

可以輕松分離測(cè)試每個(gè) VC / VM,因?yàn)橐磺卸伎梢宰⑷?。沒有必要子類化。

現(xiàn)在,在一些架構(gòu)中也有類似的概念,如 VIPER 有路由器。但它們通常是很復(fù)雜的,需要大量的前期成本,以適配到現(xiàn)有的應(yīng)用程序中。

這個(gè)方法最棒的地方是它很簡單直觀,立刻就可以(在現(xiàn)有的項(xiàng)目中)使用它,無需等待新項(xiàng)目。它在小型和大型項(xiàng)目的效果一樣好。

不管你使用 MVVM,MVC 還是其他模式,如果應(yīng)用中存在界面跳轉(zhuǎn),不妨試一試。


作者信息

原文作者:Krzysztof Zab?ocki
原文鏈接:http://merowing.info/2016/01/improve-your-ios-architecture-with-flowcontrollers/
翻譯自 MaxLeap 團(tuán)隊(duì)_UX成員:Alex Sun
翻譯首發(fā)鏈接:https://blog.maxleap.cn/archives/879

商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明作者信息與出處。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/11749.html

相關(guān)文章

  • 移動(dòng)端開發(fā):架構(gòu)那點(diǎn)事!

    摘要:移動(dòng)精英開發(fā)社群的第期,也是圍繞架構(gòu)這個(gè)話題進(jìn)行討論。本次我們希望結(jié)合實(shí)際開發(fā)中遇到的問題,來聊聊移動(dòng)端的架構(gòu)設(shè)計(jì)。這樣的模式改進(jìn)一些,可能會(huì)更適合移動(dòng)端架構(gòu)。潘衛(wèi)杰之前我們公司移動(dòng)端的大項(xiàng)目就是插座式開發(fā)的,批量出各個(gè)行業(yè)的。 此前,58 同城的技術(shù)委員會(huì)執(zhí)行主席沈劍在 OneAPM 的技術(shù)公開課上分享過一個(gè)主題,「好的架構(gòu)不是設(shè)計(jì)出來的,而是演技出來的」。因?yàn)閷?duì)很多創(chuàng)業(yè)公司而言,隨...

    KnewOne 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<