Swift学徒

iOS 架构模式之 MVVM

MVVM 构成

MVVM 看上去和 MVP 很像:

显然,MVVM 也将 ViewController 视为 View。之前我们说了 MVC 中的 Controller 里有大量表示逻辑,ViewModel 就是承载这些表示逻辑的东西。

MVVM 的 ViewModel 和 MVP的 Presenter 相比,多了数据绑定机制。一旦 ViewModel 所对应的 Model 发生变化,ViewModel 的属性也会发生变化,而相对应的 View 也随即产生变化。绑定机制既有很明显的强大优点——自动连接 View 和 Model,也有很明显的缺点——更高的耦合度,更复杂的代码逻辑。

绑定

实现绑定一般有两种方式:

实例

FRF 框架 和 KVO过度复杂,我们使用 showGreeting 方法 和 greetingDidChange 回调方法来达成这个目的。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import UIKit
struct Person { // Model
let firstName: String
let lastName: String
}
protocol GreetingViewModelProtocol: class {
var greeting: String? { get }
var greetingDidChange: ((GreetingViewModelProtocol) -> ())? { get set } // function to call when greeting did change
init(person: Person)
func showGreeting()
}
class GreetingViewModel : GreetingViewModelProtocol {
let person: Person
var greeting: String? {
didSet {
self.greetingDidChange?(self)
}
}
var greetingDidChange: ((GreetingViewModelProtocol) -> ())?
required init(person: Person) {
self.person = person
}
func showGreeting() {
self.greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
}
}
class GreetingViewController : UIViewController {
var viewModel: GreetingViewModelProtocol! {
didSet {
self.viewModel.greetingDidChange = { [unowned self] viewModel in
self.greetingLabel.text = viewModel.greeting
}
}
}
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self.viewModel, action: "showGreeting", forControlEvents: .TouchUpInside)
}
// 布局代码
}
// MVVM
let model = Person(firstName: "David", lastName: "Blaine")
let viewModel = GreetingViewModel(person: model)
let view = GreetingViewController()
view.viewModel = viewModel

抛开绑定机制不说,ViewModel 做的就是表示逻辑的载体,最简单的实现就是在 ViewController 中调用:

1
self.greetingLabel.text = self.viewModel.greeting

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

  1. 职能均分:分隔的很清楚。事实上,MVVM的View要比MVP中的View承担的责任多。因为前者通过ViewModel的设置绑定来更新状态,而后者只监听Presenter的事件但并不会对自己有什么更新。
  2. 容易测试:确实易于测试。如果我们没有将表示逻辑移入 ViewModel,我们将不得不实例化一个完整的 ViewController 以及伴随的 View,然后去比较我们 View 中的数值。但另一方面,数据绑定机制使得 定位 bug 变得更难了。数据绑定使程序异常能快速的传递到其他位置,在 View 上发现的 bug 有可能是由 ViewModel 造成的,也有可能是由 Model 造成的,传递链越长,对 Bug 的定位就越困难。
  3. 易用,维护成本低:在我们例子中的代码量和 MVP 的差不多,但是在实际开发中,使用了诸如 ReativeCocoa 这样的第三方库 ,MVVM 代码量将会小的多。

架构模式选择

没有完美的架构模式,只有适用于你的 App 业务场景和团队的架构模式。比如数据逻辑简单、注重视觉展示的页面,原始的 MVC 可能是最优解。而 MVP 的特点是有更好的灵活性和扩展性。MVVM 可以兼容当前使用 MVC架构模式 。


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