走进MVVM

MVVM与MVC有什么不一样

1.多了一个"视图模型"类前端

2.视图控制器再也不对模型具备访问权限,而是经过新的ViewModel交互bash

3.为了解决复杂的View/ViewContoller,以便于单独的访问和测试,符合模块化开发的思想架构

带来哪些变化

MVVM是一个前端架构,它专一于将用户界面的开发与业务逻辑的开发工做分离app

咱们专一于使用更好的架构提升代码质量,提升代码的可测试性,让架构设计清晰合理。市面上有那么多架构,咱们没法一一的去彻底掌握每个架构的操做,可是咱们能够记住一个简单的规则:ide

no matter what architecture we decide to use, the ultimate goal is to make test simpler.模块化

MVVM由John Gossman于2005年提出.MVVM的主要目的是将数据状态从View移动到ViewModel。布局

根据定义,View仅包含视觉元素,咱们只执行布局,动画,初始化UI组件等操做。在View和Model之间有一个称为ViewModel的特殊层。ViewModel提供了一组接口,每一个接口表明View中的UI组件。咱们使用一种称为“绑定”的技术将UI组件链接到ViewModel接口。所以,在MVVM中,咱们不直接触摸View,咱们在ViewModel中处理业务逻辑,所以View会相应地更改自身。
测试


如上图。一般,ViewModel从View接收用户交互,从Model中获取数据,而后将数据处理为一组准备显示的属性。观察ViewModel的更改后,View会自动更新。这就是MVVM的整个故事。
动画

具体来讲,对于iOS开发中的MVVM,UIView / UIViewController表明View。(这里去理解MVVM就是从视图层去弱化数据逻辑,分理出一个ViewModel接口层去处理复杂逻辑,View只专一于UI内容和数据绑定)咱们只作:ui

  1. 启动/布局/呈现UI组件。

  2. 使用ViewModel绑定UI组件。

另外一方面,在ViewModel中,咱们作:

  1. 编写控制器逻辑,例如分页,错误处理等。

  2. 编写表示逻辑,为View提供接口。

实现数据绑定

使用代理方法实现View和ViewModel的数据双向绑定

ViewController

import UIKit
class ViewController: UIViewController {
    
    var viewModel: ViewModel!
    @IBOutlet weak var userField: UITextField!
    @IBOutlet weak var passField: UITextField!
    @IBOutlet weak var repestField: UITextField!
    @IBOutlet weak var userLab: UILabel!
    @IBOutlet weak var passLab: UILabel!
    @IBOutlet weak var repestLab: UILabel!
    @IBOutlet weak var loginBtn: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        userField.addTarget(self, action: #selector(userObserver(_:)), for: .editingChanged)
        passField.addTarget(self, action: #selector(passObserver(_:)), for: .editingChanged)
        repestField.addTarget(self, action: #selector(repeatObnserver(_:)), for: .editingChanged)
        viewModel = ViewModel()
        viewModel?.delegate = self
        reloadViews()
    }

    // 须要操做,以后经过传入的数据进行数据操做
    @objc func userObserver(_ tx: UITextField) {
        viewModel?.validatedUsername(user: tx.text ?? "")
    }
    @objc func passObserver(_ tx: UITextField) {
        viewModel?.validatedPassword(pass: tx.text ?? "")
    }
    @objc func repeatObnserver(_ tx: UITextField) {
        viewModel?.validatedPasswordRepeated(repeatpass: tx.text ?? "")
    }
    @IBAction func goButton(_ sender: UIButton) {
        viewModel?.login()
    }
}

//MARK: ViewModelDelegate
extension ViewController: ViewModelDelegate {
    //双向绑定用于刷新
    func reloadViews() {
        userLab.backgroundColor = viewModel.userColor
        passLab.backgroundColor = viewModel.passColor
        repestLab.backgroundColor = viewModel.repeatpassColor
        loginBtn.isEnabled = viewModel.loginButtonEnable
        loginBtn.setTitleColor(viewModel.loginButtonBack, for: .normal)
        loginBtn.backgroundColor = viewModel.loginButtontextColor
    }
    func alertInfo() {
        
    }
    func moveToHomeScreen() {
        let alert = UIAlertController(title: "提示", message: "条件成立", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
        alert.addAction(UIAlertAction(title: "Sign out", style: .destructive, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}
复制代码


ViewModel

import UIKit
import Foundation
@objc protocol ViewModelDelegate {
    //外部响应
    //在内部实现,方法过程在外部
    func reloadViews()//
    func alertInfo()
    func moveToHomeScreen()
}

class ViewModel: NSObject {
    weak var delegate: ViewModelDelegate?
    /// 这一部分是须要ViewController调用的地方
    var userColor: UIColor? {
        return datedUsername ? UIColor.green : UIColor.red
    }
    var passColor: UIColor? {
        return datedPassword ? UIColor.green : UIColor.red
    }
    var repeatpassColor: UIColor? {
        return datedPasswordRepeated ? UIColor.green : UIColor.red
    }
    var loginButtonBack: UIColor? {
        return datedUsername && datedPassword && datedPasswordRepeated ? UIColor.black : UIColor.white
    }
    var loginButtontextColor: UIColor? {
        return datedUsername && datedPassword && datedPasswordRepeated ? UIColor.white : UIColor.black
    }
    //当三个条件都成立
    var loginButtonEnable: Bool {
        return datedUsername && datedPassword && datedPasswordRepeated
    }
    var preate: String!
    // 输出
    var datedUsername: Bool! = false
    var datedPassword: Bool! = false
    var datedPasswordRepeated: Bool! = false

    /*
     viewModel判断条件
    */
    func validatedUsername(user: String?) {
        if (user?.count)! <= 0 || (user?.count)! > 6 {
            datedUsername = false
        }else {
            datedUsername = true
        }
        delegate?.reloadViews()
    }
    func validatedPassword(pass: String?) {
        preate = pass
        if (pass?.count)! <= 0 || (pass?.count)! > 6 {
            datedPassword = false
        }else {
            datedPassword = true
        }
        delegate?.reloadViews()
    }
    func validatedPasswordRepeated(repeatpass: String?) {
        if repeatpass != preate {
            datedPasswordRepeated = false
        }else {
            datedPasswordRepeated = true
        }
        delegate?.reloadViews()
    }
    func login() {
        delegate?.moveToHomeScreen()
    }
}复制代码

最后

按照咱们看到的,ViewModel作了哪些事:

// c输出  (UI响应)
var userColor: UIColor? { get }
var passColor: UIColor? { get }
var repeatpassColor: UIColor? {get}
var loginButtonBack: UIColor? {get}
var loginButtontextColor: UIColor? {get}
var loginButtonEnable: Bool { get }
复制代码

// 输入 (逻辑处理)
func validatedUsername(user: String?)
func validatedPassword(pass: String?)
func validatedPasswordRepeated(repeatpass: String?)
func login()复制代码

//数据绑定过程
protocol ViewModelDelegate复制代码
相关文章
相关标签/搜索