Swift学徒

iOS 架构模式之 MVC

注1:本文中实例引述自《iOS Architecture Patterns》

注2:本系列从 M、V、C 角色定义以及数据流向的层面探讨架构设计。

为什么要考虑架构模式

如果不关心架构模式,总有一天,你的一个复杂类会变得无比庞大,你会发现很难修改这个类的功能,无法快速的定位 bug。

一个优秀的架构应该具备以下几个特点:

  1. 职能均衡的划分给具有清晰角色的功能类(雨露均沾)。
  2. 容易测试(往往得益于第一点)
  3. 易用,方便维护。

为什么要划分职能

当我们理解事物的时候,划分职能让我们的大脑清晰的思考。如果你认为不断的写代码,你的大脑就能习惯复杂的思维,是这样的。但是,这种思维能力并不是线性增长的,而且很快会到达瓶颈。所以,能够解决复杂问题的简单的方法就是:遵循单一功能原则 ,将职能划分给不同的功能类。

为什么要易用

易用和易维护是针对团队而言的。团队成员要对架构模式达成共识,这样才能快速有效的进行开发和 Debug。在一个准备使用一个看上去很棒的解决方案时也要考虑它的维护成本。

主流架构模式

目前几种主流的架构设计模式:

  • MVC
  • MVP
  • MVVM
  • VIPER

架构模式没有教科书式的标准答案,关键在于架构师和团队成员达成一致认识,在遇到问题时不断的调整,跨越瓶颈。

MVC

苹果的 MVC

这里我们说得 MVC 特指苹果推荐的 MVC 模式,如图:

Controller 介于 View 和 Model 之间, View 和 Model 没有任何直接联系。Model 包含了数据模型,以及管理这些数据相关的逻辑计算,如本地数据变化、数据缓存等。

这种模式很直接,并且易学。这种模式看上去很美好,但现实中,这个模式往往变成了这样的:

因为 Controller 包含了 ViewController 的生命周期和布局代码,很难说 View 和 Controller 是相互独立的。并且 Controller 处于桥接位置,很容易成一个可以处理任何事情的容器,变得臃肿无比。这样的 Controller 之中会有大量的 “表示逻辑”(presentation logic),就是那些将 Model 数据转换为 View 可以呈现的东西的事情,例如将一个 NSDate 转换为一个格式化过的 NSString,或者讲几个字符串拼接以便于显示的逻辑。

违背 MVC 的日常代码

经常会看到这样的代码:

1
2
var userCell = tableView.dequeueReusableCellWithIdentifier("identifier") as UserCell
userCell.configureWithUser(user)

这个 cell(View)直接调用了 Model,实际上已经违背了 MVC 模型的规则,但这种情况很普遍,以至于人们不觉得这里有什么不对。如果严格遵守 MVC 的话,要把对 cell 的配置放在 Controller 中,而不是向 cell(View) 传递一个 Model 对象。当然这会让 Controller 的体积变得更庞大。

MVC 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import UIKit
struct Person { // Model
let firstName: String
let lastName: String
}
class GreetingViewController : UIViewController { // View + Controller
var person: Person!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
}
func didTapButton(button: UIButton) {
let greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
self.greetingLabel.text = greeting
}
// 布局代码
}
// MVC
let model = Person(firstName: "David", lastName: "Blaine")
let controller = GreetingViewController()
controller.person = model;

我们评估下之前提出的架构特点:

  1. 职能均分:View 和 Controller 紧密耦合。
  2. 容易测试:紧密耦合不利于测试。
  3. 易用,维护成本低:这种模式在语言框架层就得到了苹果的支持,新手容易上手,相比其他模式代码量少,开发速度快。但随着项目变大,由于其耦和度很高,可维护性越来越差。

万恶胖为首 wechat
关注公众号(ID:SwiftBetter),进一步探讨交流。