Enum驱动的ViewControllers

最近看到这么一个博客
讲到了通过Enum来把ViewController变成一个状态机,通过状态的变化来确定或者执行对应的操作

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
class ProductListViewController: UIViewController {
enum State {
case Loading
case Empty
case Loaded([Product])
case Error(NSError)
}
var state = State.Loading {
didSet {
... update views ...
}
}
...
func loadProducts() {
state = .Loading
ProductManager.sharedManager.requestProducts(success: { products in
if products.count > 0 {
self.state = .Loaded(products)
} else {
self.state = .Empty
}
}, failure: { error in
self.state = .Error(error)
})
}
}

以上是博客中的一段代码,我觉得这是很好的一个思路,之前我们如果要做刷新类的操作(loading)时,可能
viewDidLoad里面要加开始刷新加载数据,在文件其他的方法中再次调用来实现下拉刷新或者其他条件触发
的刷新操作,借用以前看过的一个说法就是“起飞点有好多,着陆点也有好多”,不便于管理。

原博客中还说了这就是MVVM,想了一下确实是这样,不过平常见的多的都是绑定,这里需要在state didSet
里面调用会牵扯到对应状态改变的方法。

原作者确实很厉害,不过当然不只只是来夸原作者的。

原作者只是给出一个最简单的实现思路,实际使用中我觉得应该把状态的Enum定义抽出来,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum LoadState<T> {
case Loading
case Empty
case Loaded(T)
case Error(NSError)
}
protocol Loadable<T> { var state: LoadState<T> { get } }

enum LoginState {
case Admin(UserId)
case Normal(UserId)
case Guest
}

protocol UserRole { var state: LoginState { get } }

大概意思就是所有该类型的ViewController通过实现对应的protocol持有enum,通过protocol
名字或者enum定义来增强可读性