一看就懂的極簡MVVM

什麼是MVVM

Model-View-ViewModel(MVVM)是基於MVC的變形的一種設計模式,它由Model、View、ViewModel三部分組成,三部分的職責以下:git

  • Model:負責表現應用的數據,它們一般是struct或者class。官方推薦使用struct定義Model。具體詳情可點擊這裏
  • View:負責顯示在屏幕上的可視化元素,一般是UIView的子類。
  • ViewModel:負責將Model中的數據轉化爲View上顯示的數據。它們一般是class,這樣它們就能夠經過引用指針來傳遞。

具體邏輯以下圖:github

爲何要使用MVVM

當咱們在項目初創時期,用MVC搭建項目是沒有問題的。可是隨着項目業務愈來愈多,愈來愈複雜的時候,咱們會發現Controller裏面的東西會很是的多,它一般會包含:Controller的生命週期函數、視圖的響應事件、遠程數據的獲取,數據的變形,各類邏輯的判斷等等。這樣會致使代碼閱讀性降低,bug率提高。這也是爲何你們調侃MVC爲Massive-View-Controller的緣由。swift

在這個背景下就誕生了MVVM設計模式來解決Massive Controller的問題,在使用MVVM的模式時,咱們能夠把數據轉換、數據邏輯判斷放在ViewModel裏,以此來減輕Controller的負擔。設計模式

開始搭建MVVM

一、首先咱們新建一個項目,建立一個Person.swift文件來表示用戶的數據:bash

//定義一個包含用戶名字、頭像和註冊時間的結構體當作用戶的Model
struct Person {
    let name: String
    let image: String
    let registerTimeStamp: TimeInterval
}
複製代碼

二、接下來咱們建立負責轉換Model的ViewModel-PersonViewModel.swift:架構

// name 和 image 只是簡單的經過兩個計算屬性來接受
// 將時間戳的註冊時間轉換爲字符串的註冊時間
class PersonViewModel {
    let person: Person
    
    private var name: String {
        return person.name
    }
    
    private var image: String {
        return person.image
    }
    
    private var registerTimeStr: String {
        let date = Date(timeIntervalSince1970: person.registerTimeStamp)
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
        let strDate = dateFormatter.string(from: date)
        return strDate
    }
    
    init(_ person: Person) {
        self.person = person
    }
}
複製代碼

三、建立展現用戶信息的PersonView.swift:app

class PersonView: UIView {
    
    let imageView = UIImageView()
    let nameLabel = UILabel()
    let registerTimeLabel = UILabel()
    

    override init(frame: CGRect) {
        super.init(frame: frame)
        
        backgroundColor = UIColor.brown
        
        imageView.frame = CGRect(x: (frame.width - 50)/2, y: 10, width: 50, height: 50)
        addSubview(imageView)
        
        nameLabel.frame = CGRect(x: 0, y: 80, width: frame.width, height: 20)
        nameLabel.textAlignment = .center
        addSubview(nameLabel)
        
        registerTimeLabel.frame = CGRect(x: 0, y: 110, width: frame.width, height: 16)
        registerTimeLabel.font = UIFont.systemFont(ofSize: 14)
        registerTimeLabel.textColor = UIColor.lightGray
        registerTimeLabel.textAlignment = .center
        addSubview(registerTimeLabel)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
複製代碼

四、最後一步,在Controller中將它們鏈接起來:ide

class ViewController: UIViewController {

    let personView = PersonView(frame: CGRect(x: (UIScreen.main.bounds.size.width - 200)/2, y: (UIScreen.main.bounds.size.height - 300)/2, width: 200, height: 300))
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.white

        setupSubViews()
        requestData()
    }
    
    func setupSubViews() {
        view.addSubview(personView)
    }
    
    func requestData() {
        let person = Person(name: "godiscoder", image: "head_default", registerTimeStamp: 1480134638.0)
        let viewModel = PersonViewModel(person)
        
        personView.imageView.image = UIImage(named: viewModel.image)
        personView.nameLabel.text = viewModel.name
        personView.registerTimeLabel.text = viewModel.registerTimeStr
    }

}
複製代碼

好啦,到如今爲止你已經實踐了MVVM的設計模式,若是不出意外的話你會在你的模擬器上顯示一個展現用戶信息的view,以下圖: 函數

五、固然,咱們能夠把給view賦值的語句放在PersonViewModel,這樣可使代碼更加解耦。ui

// 在PersonViewModel 最下方 添加
extension PersonViewModel {
    func configurate(_ personView: PersonView) {
        personView.imageView.image = UIImage(named: image)
        personView.nameLabel.text = name
        personView.registerTimeLabel.text = registerTimeStr
    }
}

// 將 ViewController裏的requestData()的代碼更新爲下面的代碼
 func requestData() {
    let person = Person(name: "godiscoder", image: "head_default", registerTimeStamp: 1480134638.0)
    let viewModel = PersonViewModel(person)
    viewModel.configurate(personView)
}
複製代碼

完整代碼能夠在這裏下載。

總結

當你的項目業務比較簡單的時候仍是推薦使用MVC架構,當業務比較複雜的時候能夠轉爲MVVM架構。

相關文章
相關標籤/搜索