Swift 如何在 Protocol 中使用 @Published 屬性包裹類型

本文的知識須要依賴 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,經過 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 三班
複製代碼

但願本文能對你帶來幫助,😸!!!

相關文章
相關標籤/搜索