import Foundation
protocol ICategoryService {
func getCategoryById(id: Int) -> Category?
}
class CategoryService: ICategoryService {
func getCategoryById(id: Int) -> Category? {
let categories = [Category(id: 3, name: "Movies"),
Category(id: 4, name: "Books"),
Category(id: 5, name: "Computer")]
let category = categories.filter({
$0.id == id
}).first
return category
}
}
ViewModel Layer
import Foundation
import RxSwift
class HomeViewModel {
var category: Category
var service: ICategoryService
var displayName: String {
return transformName(category.name)
}
// 1
var valueSubject: PublishSubject<String>
init(category: Category, service: ICategoryService) {
self.category = category
self.service = service
valueSubject = PublishSubject()
}
func transformName(_ name: String) -> String {
let newName = name.enumerated().map { (index, character) -> String in
if index % 2 == 0 {
return character.uppercased()
} else {
return character.lowercased()
}
}
return newName.joined()
}
// 2
func getCategory(id: Int) {
if let newCategory = service.getCategoryById(id: id) {
self.category = newCategory
valueSubject.onNext(transformName(category.name))
}
}
}
Khởi tạo 1 subject kiểu Publish Subject để phát ra các event khi giá trị của category’s name được thay đổi.
ViewModel sẽ thông qua Model Layer để truy xuất đến database. Sau khi lấy được data cần thiết, thì valueSubject sẽ phát ra 1 event có giá trị là name đã được transform của category mới.
Tap button để yêu cầu viewModel lấy ra 1 category có id = 3.
Tác dụng của MVVM:
Tương tự như MVP, lợi ích đầu tiên của MVVM là tách biệt phần logic ra khỏi View. Từ đó dẫn đến dễ viết unit test, dễ maintain, …
Dễ dàng reuse các ViewModel.
Bằng việc tương tác với View thông qua cơ chế data binding, vì vậy không cần tạo thêm nhiều protocol, class…
MVVM vs MVP:
Trong MVVM, vì ViewModel tương tác với View bằng data binding, vì vậy ViewModel không có 1 reference nào đến View. Từ đó ViewModel sẽ dễ dàng được reuse, dễ dàng viết test hơn so với MVP.
Presenter và View là liên kết chặt với quan hệ 1:1 trong MVP Quan hệ giữa ViewModel và View trong MVVM
Trong MVVM, 1 View có thể có nhiều ViewModel.
MVVM sẽ không cần phải tạo nhiều protocol như MVP.
Việc sử dụng cơ chế data binding cũng dẫn đến 1 hệ quả là MVVM sẽ khó để debug hơn nhiều so với việc sử dụng MVP.
Nếu sử dụng RxSwift kết hợp với MVVM, thì sẽ phải đòi hỏi team của bạn đều phải biết RxSwift ở mức ổn.
Kết luận:
Mục tiêu chính của MVVM là tách biệt logic khỏi View. Tuy nhiên, những phần logic như truy vấn database, networking, … thì chưa được xử lí. Những logic như vậy có thể được đặt ở presenter, hoặc tạo 1 class riêng ở Model tùy theo bản thân bạn. Tuy nhiên, nên tách biệt các phần logic Database, networking, … ra các class riêng để tuân thủ nguyên tắc Single Responsibility Principle của SOLID.
Theo nguyên tắc MVVM thì ViewModel không import UIKit để tách biệt logic và View.