本文的知识需要依赖 Combine 框架的相关知识。
对于项目中的 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 = "张三"
简单的说一下上面的代码在做什么:
1、导入依赖的框架
2、定义一个带有 Published 的数据模型
3、在控制器中接受该模型的通知
输出结果:
hello 王二麻子
hello 李四
hello 张三
通过输出结果可以看到代码逻辑正如我们所愿。
但如果我们需要定义一个 Protocol 来进行扩展呢,只要遵守该协议的数据类型就能被 View Controller 监听,那么该如何实现呢?
实现 Protocol 中使用 @Published 属性包裹类型
1、定义 Protocol,通过 Published 将我们的实际类型包裹起来。
protocol CommonViewModel {
var namePublisher: Published<String>.Publisher { get }
}
2、数据类型遵守该协议,将 name 的值返回给 namePublisher。
class MyViewModel: CommonViewModel {
@Published var name: String
var namePublisher: Published<String>.Publisher { $name }
init(name: String) {
self.name = name
}
}
3、先将 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)
}
}
4、执行代码,代码逻辑执行正常:
hello 王二麻子
hello 李四
hello 张三
5、再添加一种别的 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 三班
希望本文能对你带来帮助,😸!!!