此实现方式为并不完全的MVVM,绑定耦合性较高。架构更偏向于MVP。只是因为团队对于MVVM和RxSwift or RAC不熟悉,RxSwift or RAC学习成本较高,此实现方式为中间过渡状态。
通过delegate形式实现反向绑定,容易理解,在本次项目中,让团队成员有更无痛的方式体验MVVM并逐步掌握此架构分层思想。
待熟练掌握MVVM结构后,后续项目逐步使用RxSwift开发。
实现方式:
1.ViewController中声明ViewModel,例如
ABCViewController
let viewModel: ABCViewModel = ABCViewModel()
2.配置viewModel的代理
viewModel.delegate = self
3.viewModel中声明协议
protocol ABCViewModelProtocol
func titleChanged:(value: String)
3.viewModel中声明代理、UI展示内容的成员变量,并通过代理通知VC相关属性变化
var delegate: ABCViewModelProtocol?
var titleStr: String {
didSet {
if oldValue != titleStr {
delegate?.titleChanged(value: titleStr)
}
}
}
4.ViewController中遵守代理协议,实现代理方法,并在此处更新UI展示内容即可
extension ABCViewController: ABCViewModelDelegate {
func titleChanged(value: String) {
titleLabel.text = value
}
}
此MVVM中,View主要负责展示数据,因此,View中只有UI相关的东西,通过ViewModel将处理好的数据传递给View直接展示,不需要对数据做任何处理。
Controller和View的逻辑基本一致,只展示UI相关,还有页面跳转,push、pop、present等操作。在我们现在的实现中,他还负责不同VC间的跨页面传值,通过func接受别的页面传递的数据并直接传递给自己的viewModel。从Android端的实现中,找到了另一种实现方式,shareViewModel,通过共享的或全局的一个对象,供不同的ViewModel分享需要传递的值。
View+Controller统一称为View层,这一层持有ViewModel,并作为ViewModel的代理对数据变化做出响应。
ViewModel主要负责处理数据、业务逻辑,将从网络请求到的数据或从别的页面传递过来的数据,经过数据加工,传递给View层去展示。ViewModel层不应出现任何UI相关的内容,因此,不要import UIKit。ViewModel层还负责处理View层传入的事件的逻辑处理,以及提供View层需要的非响应性的数据。ViewModel层持有Model,原则上来说,非必要情况下尽量不要将Model传递给View层,但Microsoft 的 MVVM中也说明,在特殊情况下,可以传递。但,尽量不要传递,会增加耦合。
Model主要负责获取数据,从网络或数据库中拉取数据,并将Json转换为String或Object形式,传递到ViewModel层中。
我们的实现方式中,为了省事,让ViewModel做了获取数据的事情,Model层很薄,只做了Json mapping的事。这是不好的,让ViewModel更加像MVC中的Controller。但这样做,会省去ViewModel和Model的绑定。但是,还是不好的。
实践中,要保持基本MVVM架构,通过代理实现数据绑定,并保证View中的UI变化是通过ViewModel中的数据变化,经过代理通知到UI并作出改变。因此,不应该出现在View中,不通过代理直接改变UI内容的情况(一般情况下)。
此种实现方式并不完善,数据绑定很勉强,还因为写大量的代理,增加了代码量。但在保证MVVM架构正常的情况下,各层间逻辑清晰,数据传递明确,代码质量和纯洁度会有所提高。并且ViewModel脱离UI存在,对复用和业务逻辑可测提供了很大的帮助。最重要的一点,让团队通过此中间过渡的实现方案,对MVVM有了初步的了解,并在开发过程中,对此种模式逐步适应。为以后MVVM+RxSwift实现方式打好了基础。