如何更新视图状态以响应外部更改?
How can I update view state in response to external changes?
假设我有一个具有某些可变状态的视图,但可能需要更新该状态以反映另一个对象(例如 ViewModel
)中的更改。
如何在 SwiftUI 中实现它?
我尝试了以下方法,但无法获得反映来自 ViewModel
:
的更新的视图
class ViewModel: ObservableObject {
@Published var text: String = "loading"
private var task: AnyCancellable?
func fetch() {
task = Just("done")
.delay(for: 1, scheduler: RunLoop.main)
.assign(to: \.text, on: self)
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
@State var viewText = "idle"
private var bind: AnyCancellable?
init() {
viewText = viewModel.text
bind = viewModel
.$text
.print()
.assign(to: \.viewText, on: self)
}
var body: some View {
VStack {
TextField(titleKey: "editable text", text: $viewText)
Text(viewText)
Text(viewModel.text)
}
.onAppear {
self.viewModel.fetch()
}
}
}
TextField
和第一个 Text
元素从 ContentView.viewText
获取内容,第二个 Text
直接转到源:ViewModel.text
.
正如预期的那样,第二个 Text
显示 "loading"
,然后是 "done"
。第一个 Text
永远不会从 "idle"
改变。
这是可能的方法(测试并适用于 Xcode 11.2 / iOS 13.2)- 仅修改 ContentView
:
struct ContentView: View {
@ObservedObject var viewModel = ViewModelX()
@State private var viewText = "idle"
init() {
_viewText = State<String>(initialValue: viewModel.text)
}
var body: some View {
VStack {
Text(viewText)
Text(viewModel.text)
}
.onReceive(viewModel.$text) { value in
self.viewText = value
}
.onAppear {
self.viewModel.fetch()
}
}
}
如果下一个屏幕录制看起来像是在回答您的问题
它是使用下一个代码记录的
import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var text: String = "loading"
private var task: AnyCancellable?
func fetch() {
task = Just("done")
.delay(for: 3, scheduler: RunLoop.main)
.assign(to: \.text, on: self)
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
@State var viewText = "idle"
var body: some View {
VStack {
Text(viewText)
Text(viewModel.text)
}.onReceive(viewModel.$text.filter({ (s) -> Bool in
s == "done"
})) { (txt) in
self.viewText = txt
}.onAppear {
self.viewModel.fetch()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
假设我有一个具有某些可变状态的视图,但可能需要更新该状态以反映另一个对象(例如 ViewModel
)中的更改。
如何在 SwiftUI 中实现它?
我尝试了以下方法,但无法获得反映来自 ViewModel
:
class ViewModel: ObservableObject {
@Published var text: String = "loading"
private var task: AnyCancellable?
func fetch() {
task = Just("done")
.delay(for: 1, scheduler: RunLoop.main)
.assign(to: \.text, on: self)
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
@State var viewText = "idle"
private var bind: AnyCancellable?
init() {
viewText = viewModel.text
bind = viewModel
.$text
.print()
.assign(to: \.viewText, on: self)
}
var body: some View {
VStack {
TextField(titleKey: "editable text", text: $viewText)
Text(viewText)
Text(viewModel.text)
}
.onAppear {
self.viewModel.fetch()
}
}
}
TextField
和第一个 Text
元素从 ContentView.viewText
获取内容,第二个 Text
直接转到源:ViewModel.text
.
正如预期的那样,第二个 Text
显示 "loading"
,然后是 "done"
。第一个 Text
永远不会从 "idle"
改变。
这是可能的方法(测试并适用于 Xcode 11.2 / iOS 13.2)- 仅修改 ContentView
:
struct ContentView: View {
@ObservedObject var viewModel = ViewModelX()
@State private var viewText = "idle"
init() {
_viewText = State<String>(initialValue: viewModel.text)
}
var body: some View {
VStack {
Text(viewText)
Text(viewModel.text)
}
.onReceive(viewModel.$text) { value in
self.viewText = value
}
.onAppear {
self.viewModel.fetch()
}
}
}
如果下一个屏幕录制看起来像是在回答您的问题
它是使用下一个代码记录的
import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var text: String = "loading"
private var task: AnyCancellable?
func fetch() {
task = Just("done")
.delay(for: 3, scheduler: RunLoop.main)
.assign(to: \.text, on: self)
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
@State var viewText = "idle"
var body: some View {
VStack {
Text(viewText)
Text(viewModel.text)
}.onReceive(viewModel.$text.filter({ (s) -> Bool in
s == "done"
})) { (txt) in
self.viewText = txt
}.onAppear {
self.viewModel.fetch()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}