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
启动/布局/呈现UI组件。
使用ViewModel绑定UI组件。
另外一方面,在ViewModel中,咱们作:
编写控制器逻辑,例如分页,错误处理等。
编写表示逻辑,为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复制代码