iOS MVVM 实践

为什么要用MVVM替代MVC

在MVC模式中,Controller由于承担了过多的事务,包括页面展示逻辑和业务逻辑,往往会变的臃肿不堪,成为一个人们所说的重量级视图控制器。臃肿的ViewController难以理解,难以维护,难以扩展,增加了后续开发的复杂度,降低了整体开发的效率。

什么是MVVM

MVC

MVC(Model-View-Controller)是最经典的架构模式,其中Model是作为数据管理者,View作为数据展示者,Controller作为数据加工者,Model和View又都是由Controller来根据业务需求调配,所以Controller还负担了一个数据流调配的功能。

MVCS

MVCS是基于MVC衍生出来的一套架构。从概念上来说,它拆分的部分是Model部分,拆出来一个Store。这个Store专门负责数据存取。

MVVM

MVVM本质上也是从MVC中派生出来的,它是一个精心优化的MVC架构。它把数据加工的任务从Controller中解放了出来,使得Controller只需要专注于数据调配的工作,ViewModel则去负责数据加工并通过通知机制让View响应ViewModel的改变。大部分MVVM架构都会使用ReactiveCocoa,ReactiveCocoa带来了信号通知效果。



当然MVVM也有缺点,数据绑定机制让调试更困难,界面上出现的bug,可能是view的代码有问题,也可能是model有问题。数据绑定机制让一个位置的bug快速传递到其它位置上,定位原始出问题的地方不那么容易。而且数据绑定需要花费更大的内存。MVVM的学习和开发成本也很高,大家对它不熟悉,基于绑定机制进行编程需要一定时间的学习才能上手。

MVVM简化版

MVVM简化版是在MVC和MVVM两种架构中权衡而产生的架构。它引用了ViewModel,将表示逻辑移到ViewModel中。一个view对应一个ViewModel,其包含了这个View数据展示和样式定制所需要的所有数据。同时,不再引用双向数据绑定机制,而使用传统的代理回调将ui事件传递给外界。这个架构中,ViewModel负责处理数据展示和样式定制的逻辑; ViewController仅仅负责数据流调配。
MVVM简化版有以下三个优点:

  • 简单,易学易用,上手成本低
  • 兼容MVC模式
  • 提高应用的可测试性

怎么使用MVVM

下面我们用MVVM简化版写一个简单的demo,看看它是如何工作的。
这是一个获取最新天气的demo,为简单起见,只显示今天的天气。从服务返回的json格式如下:

  ......
  "today": {
            "temperature": "28℃~38℃", 
        "date_y": "2016年08月19日", 
            "weather_id": {
                "fa": "00", 
                "fb": "00"
            }, 
            "city": "杭州", 
  ......
        }

要求在页面上按MMDD格式显示日期,天气情况不能用00、01直接显示,要转换一下。这些都属于展示逻辑。我们将它从ViewController中移到ViewModel中。
首先建立一个Weather model,它仅仅定义了几个属性来表达数据,没有任何数据加工的部分。

struct Weather {
    var location: String? //位置
    var date: String?   //日期
    var iconText: String?   //天气图标
    var temperature: String?    //温度
}

WeatherViewModel有自己的属性,提供给对应的View。它传入weather model,加工数据以满足view需要。

class WeatherViewModel: NSObject {
    
    var date: String?
    var iconText: String?
    var loction: String?
    var temperature: String?
......

展示逻辑的处理如下:

    class func viewModelWith(weather: Weather) -> WeatherViewModel{
        let date = weather.date?.toDate(DateFormat.Custom("yyyy年MM月dd日"))
        
        var iconText = ""
        switch weather.iconText! {
        case "00":
            iconText = "晴"
        case "01":
            iconText = "多云"
        case "02":
            iconText = "阴"
        case "03":
            iconText = "阵雨"
        case "04":
            iconText = "雷阵雨"
        case "07":
            iconText = "小雨"
        case "08":
            iconText = "中雨"
        case "09":
            iconText = "大雨"
        case "10":
            iconText = "暴雨"
        case "11":
            iconText = "特大暴雨"
        case "21":
            iconText = "小雨-中雨"
        case "22":
            iconText = "中雨-大雨"
        case "23":
            iconText = "大雨-暴雨"
        default: break
        }
        
        let wvm = WeatherViewModel()
        wvm.date = String(date!.month) + "\\" + String(date!.day)
        wvm.loction = weather.location
        wvm.temperature = weather.temperature
        wvm.iconText = iconText
        return wvm
    }

View只需要定义好装配ViewModel的接口和定义好UI回调事件即可。

class WeatherView: UIView {

    var timeLbl: UILabel!
    var iconLbl: UILabel!
    var temperationLbl: UILabel!
    var cityLbl: UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func bindDataWithViewModel(weatherViewModel: WeatherViewModel){
        timeLbl.text = weatherViewModel.date
        iconLbl.text = weatherViewModel.iconText
        temperationLbl.text = weatherViewModel.temperature
        cityLbl.text = weatherViewModel.loction
    }
......

ViewController管理View Controller的生命周期,负责生成所有的View实例,并放入到View Controller中。监听处理来自View和业务相关的事件。

......
let weather = Weather(location: location, date: date, iconText: icon, temperature: temperature)
                let wv = WeatherViewModel.viewModelWith(weather)
                
                self.todayView.bindDataWithViewModel(wv)
......

demo的源码在这里:[https://github.com/superzcj]

总结

MVVM将展示和业务逻辑从Controller中移到ViewModel,为Controller减轻了负担,使代码结构更清晰,职责更明确,同时使代码更易于测试。
简化的MVVM也能跟现有的MVC应用兼容,不会对MVC模式带来太多变化,只是把部分逻辑代码移动个位置。另外对于简单的业务功能,使用MVVM会频繁在各个部分传递数据,反而显得臃肿罗嗦。因此,对于简单的业务,我们仍可以用MVC模式开发,对于复杂的业务,我们使用MVVM模式拆分业务逻辑。

你可能感兴趣的:(iOS MVVM 实践)