本文的知識須要依賴 Combine 框架的相關知識。
bash
對於項目中的 MVVM 架構,一般咱們會使用 RX系列來實現。但 Combine 發佈之後,咱們多了一種選擇。經過使用 Combine 中的 @Published 修飾的屬性,也能夠實現當模型中的數據發生改變時,自動通知 View Controller。架構
下面先來看一個簡單的例子。框架
// 1.
import Combine
import PlaygroundSupport
// 2.
class MyViewModel {
@Published var name: String
init(name: String) {
self.name = name
}
}
class MyVC: UIViewController {
var vm: MyViewModel!
private var cancellables: Set<AnyCancellable> = []
override func viewDidLoad() {
super.viewDidLoad()
// 3.
vm.$name
.receive(on: RunLoop.main)
.sink { (name) in
print("hello \(name)")
}.store(in: &cancellables)
}
}
let vm = MyViewModel(name: "王二麻子")
let vc = MyVC()
vc.vm = vm
PlaygroundPage.current.liveView = vc
vm.name = "李四"
vm.name = "張三"
複製代碼
簡單的說一下上面的代碼在作什麼:ide
一、導入依賴的框架oop
二、定義一個帶有 Published 的數據模型ui
三、在控制器中接受該模型的通知spa
輸出結果:code
hello 王二麻子
hello 李四
hello 張三
複製代碼
經過輸出結果能夠看到代碼邏輯正如咱們所願。對象
但若是咱們須要定義一個 Protocol 來進行擴展呢,只要遵照該協議的數據類型就能被 View Controller 監聽,那麼該如何實現呢?get
一、定義 Protocol,經過 Published 將咱們的實際類型包裹起來。
protocol CommonViewModel {
var namePublisher: Published<String>.Publisher { get }
}
複製代碼
二、數據類型遵照該協議,將 name 的值返回給 namePublisher。
class MyViewModel: CommonViewModel {
@Published var name: String
var namePublisher: Published<String>.Publisher { $name }
init(name: String) {
self.name = name
}
}
複製代碼
三、先將 vm 的類型修改成 CommonViewModel,而後再修改 View Controller 中的接受對象。
class MyVC: UIViewController {
var vm: CommonViewModel!
private var cancellables: Set<AnyCancellable> = []
override func viewDidLoad() {
super.viewDidLoad()
vm.namePublisher
.receive(on: RunLoop.main)
.sink { (name) in
print("hello \(name)")
}.store(in: &cancellables)
}
}
複製代碼
四、執行代碼,代碼邏輯執行正常:
hello 王二麻子
hello 李四
hello 張三
複製代碼
五、再添加一種別的 View Model 看是否能通用:
class StuViewModel: CommonViewModel {
@Published var cls: String
var namePublisher: Published<String>.Publisher { $cls }
init(cls: String) {
self.cls = cls
}
}
let stuVM = StuViewModel(cls: "一班")
vc.vm = stuVM
PlaygroundPage.current.liveView = vc
stuVM.cls = "二班"
stuVM.cls = "三班"
複製代碼
輸出結果:
hello 一班
hello 二班
hello 三班
複製代碼
但願本文能對你帶來幫助,😸!!!