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 三班
复制代码

但愿本文能对你带来帮助,😸!!!

相关文章
相关标签/搜索