本文的知识须要依赖 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 三班
复制代码
但愿本文能对你带来帮助,😸!!!