mvvm - 将@Binding / @State 绑定到@Publisher 以解耦VM和View Layer
问题描述
我想解耦我的 ViewModel 和 View 层以增加我的 View 的可测试性。因此,我想将我的属性状态保持在视图内,并且只在需要时对其进行初始化。但我无法使用@Published 属性初始化我的@Binding 或@States。有没有办法将它们耦合到 init 函数中?
我只是在下面添加示例代码
代替
import SwiftUI
class ViewModel: ObservableObject {
@Published var str: String = "a"
@Published var int: Int = 1 { didSet { print("ViewModel int = \(int)")} }
init() {
print("ViewModel initialized")
}
}
struct ContentView: View {
@ObservedObject vM = ViewModel()
var body: some View {
Button(action: { vM.int += 1; print(int) }, label: {
Text("Button")
})
}
}
我想在我的视图中不使用 @ObservedObject 来实现这一点。
import SwiftUI
class ViewModel: ObservableObject {
@Published var str: String = "a"
@Published var int: Int = 1 { didSet { print("ViewModel int = \(int)")} }
init() {
print("ViewModel initialized")
}
}
struct ContentView: View {
@Binding var str: String
@Binding var int: Int
var body: some View {
Button(action: { int += 1; print(int) }, label: {
Text("Button")
})
}
}
extension ContentView {
init(viewModel:ObservedObject<ViewModel> = ObservedObject(wrappedValue: ViewModel())) {
// str: Binding<String> and viewModel.str: Published<String>.publisher
// type so that I cannot bind my bindings to viewModel. I must accomplish
// this by using @ObservedObject but this time my view couples with ViewModel
_str = viewModel.wrappedValue.$str
_int = viewModel.wrappedValue.$int
print("ViewCreated")
}
}
// Testing Init
ContentView(str: Binding<String>, int: Binding<Int>)
// ViewModel Init
ContentView(viewModel: ViewModel)
这样我就不能将它们相互绑定,我只想将我的绑定或状态属性绑定到已发布的属性。
解决方案
我已经意识到通过 Binding(get:{}, set{}),我可以做到这一点。如果有人想分离他们的 ViewModel 和 View 层,他们可以使用这种方法:
import SwiftUI
class ViewModel: ObservableObject {
@Published var str: String = "a"
@Published var int: Int = 1 { didSet { print("ViewModel int = \(int)")} }
init() {
print("ViewModel initialized")
}
}
struct ContentView: View {
@Binding var str: String
@Binding var int: Int
var body: some View {
Button(action: { int += 1; print(int) }, label: {
Text("Button")
})
}
}
extension ContentView {
init(viewModel:ViewModel = ViewModel()) {
_str = Binding ( get: { viewModel.str }, set: { viewModel.str = $0 } )
_int = Binding ( get: { viewModel.int }, set: { viewModel.int = $0 } )
print("ViewCreated")
}
}
推荐阅读
- python - Python 2.7 tkinter - 与 widget.tk_focusNext().focus() 相反
- ansible - Ansible:为文件和目录设置 ACL
- android - 有没有一种优雅的方式来保存和恢复 Kotlin 中的视图状态?
- amazon-web-services - 在轮询之前从 AWS SQS 队列中删除一些消息
- gremlin - aws 海王星因大图下降而超时 ()
- c++ - 必需:以字符串模 11 存储的大数(最多 1000 位)
- kernel - 在内核树外编译 ebpf _kern.c 并将独立的 libbpf 链接到 _user.c
- r - 使用 dplyr 删除多个变量的所有重复项
- php - Paypal - 通过更改计划或数量来修改订阅
- php - 如何修复:PHP 注意:未定义索引