IT技术干货栏——分享移动端&前端&后端编程从入门到高级iOS进阶指南iOS 开发

使用 FlowControllers 改进iOS应用架构

2016-06-02  本文已影响212人  商领云

引言

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

这个幼稚的实现存在很多问题:

我们怎样才能解决这个问题?

清理你的 ViewControllers / ViewModels

这可以应用到 MVVM,MVC 和许多其他的常见模式。当我谈到 VC / VM,思考一下你现在正在使用的那一个。

让我们使用代理或者基于 block 的接口,而不是对相关的控制器硬编码,来摆脱所有的依赖关系。

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

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

}

ViewController / ViewModel 应该:

这个时候,我们已经提高了可测试性,因为我们现在可以测试我们的接口是否被触发了,且无需副作用。伪代码:

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

但是,我们如何协调我们的应用程序视图控制器?

介绍 FlowControllers

一个 FlowController 是一个简单的对象,它将管理你的应用程序的一部分,我喜欢把它看成用例的一个子集。

FlowController 的三个主要角色是:

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 的应用架构像这样:

这个想法最初是 Jim 和 Sami 一年前介绍给我的,我们经常使用它。

尽管我们的应用剧烈改变了3次,我们的架构都轻松地应对了,我们能够重复使用大量的代码,也有不少控制器不需要任何改变。

使用这样的架构的好处是显而易见的:

现在,在一些架构中也有类似的概念,如 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

商业转载请联系作者获得授权,非商业转载请注明作者信息与出处。

上一篇 下一篇

猜你喜欢

热点阅读