SwiftUI 如何将@Published 分配给另一个@Published
SwiftUI How to assign @Published to another @Published
我有一个视图(MainView
),里面有另一个视图(FooGroupView
)。每次我单击 FooGroupView
中的项目,然后将值更改传递给 MainView
。
如下所示:
白色视图为MainView
,红色视图为FooGroupView
。如果单击 foo1
,则文本应为 Current:foo1
,如果单击 foo2
,则文本应为 Current:foo2
。
我的代码在这里:
Test.Playground
import SwiftUI
import PlaygroundSupport
struct FooRowView: View {
var foo: Foo
var body: some View {
VStack {
Color(.red)
Text(foo.name)
}
}
}
class Foo: Identifiable, ObservableObject {
var name: String
var id: String
init(name: String, id: String) {
self.name = name
self.id = id
}
}
final class FooGroupViewModel: ObservableObject {
var foos: [Foo] {
didSet {
self.selectedFoo = foos.first
}
}
@Published var selectedFoo: Foo? {
didSet {
print("You selected: \(selectedFoo?.name)")
}
}
init(foos: [Foo] = []) {
self.foos = foos
self.selectedFoo = foos.first
}
}
struct FooGroupView: View {
var viewModel: FooGroupViewModel
var body: some View {
ScrollView(.horizontal) {
HStack(alignment: .center, spacing: 32, content: {
// Error: error: Execution was interrupted, reason: signal SIGABRT.
//The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
/*ForEach(viewModel.foos) { foo in
Text(foo.name)
}*/
Text(viewModel.foos[0].name).onTapGesture {
viewModel.selectedFoo = viewModel.foos[0]
}
Text(viewModel.foos[1].name).onTapGesture {
viewModel.selectedFoo = viewModel.foos[1]
}
})
}
}
}
final class MainViewModel: ObservableObject {
@ObservedObject var fooGroupViewModel: FooGroupViewModel
@Published var currentFoo: Foo?
init() {
fooGroupViewModel = FooGroupViewModel(foos: [Foo(name: "foo1", id: "1"), Foo(name: "foo2", id: "2")])
currentFoo = self.fooGroupViewModel.selectedFoo
}
}
struct MainView: View {
@ObservedObject var viewModel = MainViewModel()
var body: some View {
VStack {
FooGroupView(viewModel: viewModel.fooGroupViewModel)
.background(Color.red)
Spacer()
Text("Current:\(viewModel.currentFoo!.name)")
}.frame(width: 200, height: 200)
}
}
PlaygroundPage.current.liveView = UIHostingController(rootView: MainView())
在MainViewModel
中如果currentFoo
有变化,那么UI应该更新。
当点击 foo1
或 foo2
时,FooGroupViewModel
中的 selectedFoo
已更新,然后 MainViewModel
中应该得到更改(如 @ObservedObject var fooGroupViewModel: FooGroupViewModel
)
我的问题是如何让currentFoo
知道fooGroupViewModel
中selectedFoo
的变化?我以为这条线可以观察 selectedFoo
的变化,如果有任何更新,则触发 currentFoo
变化并更新 UI.
currentFoo = self.fooGroupViewModel.selectedFoo
但实际上是行不通的
有什么帮助吗?谢谢!
我还有一个问题,就是上面代码中的注释(如果将我的代码粘贴到Playground中,第56行)
ForEach(viewModel.foos) { foo in
Text(foo.name)
}
此代码使 playground 错误:
// Error: error: Execution was interrupted, reason: signal SIGABRT.
//The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
控制台中没有任何其他信息。不知道为什么。感谢您的帮助。
只做 currentFoo = self.fooGroupViewModel.selectedFoo
绝对行不通 - 它只是将 selectedFoo
当时的内容分配给 currentFoo
。
根据您的设置,您需要订阅 fooGroupViewModel.selectedFoo
中的更改,这可以通过 Published
发布者完成,因为它是 @Published
属性 .
此外,请记住 @ObservedObject
仅在视图内部有意义,因此我将其删除。
import Combine
// ...
final class MainViewModel: ObservableObject {
var fooGroupViewModel: FooGroupViewModel
@Published var currentFoo: Foo?
private var cancellables: Set<AnyCancellable> = []
init() {
fooGroupViewModel = FooGroupViewModel(foos:
[Foo(name: "foo1", id: "1"), Foo(name: "foo2", id: "2")])
fooGroupViewModel.$selectedFoo
.assign(to: \.currentFoo, on: self)
.store(in: &cancellables)
}
}
我有一个视图(MainView
),里面有另一个视图(FooGroupView
)。每次我单击 FooGroupView
中的项目,然后将值更改传递给 MainView
。
如下所示:
白色视图为MainView
,红色视图为FooGroupView
。如果单击 foo1
,则文本应为 Current:foo1
,如果单击 foo2
,则文本应为 Current:foo2
。
我的代码在这里:
Test.Playground
import SwiftUI
import PlaygroundSupport
struct FooRowView: View {
var foo: Foo
var body: some View {
VStack {
Color(.red)
Text(foo.name)
}
}
}
class Foo: Identifiable, ObservableObject {
var name: String
var id: String
init(name: String, id: String) {
self.name = name
self.id = id
}
}
final class FooGroupViewModel: ObservableObject {
var foos: [Foo] {
didSet {
self.selectedFoo = foos.first
}
}
@Published var selectedFoo: Foo? {
didSet {
print("You selected: \(selectedFoo?.name)")
}
}
init(foos: [Foo] = []) {
self.foos = foos
self.selectedFoo = foos.first
}
}
struct FooGroupView: View {
var viewModel: FooGroupViewModel
var body: some View {
ScrollView(.horizontal) {
HStack(alignment: .center, spacing: 32, content: {
// Error: error: Execution was interrupted, reason: signal SIGABRT.
//The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
/*ForEach(viewModel.foos) { foo in
Text(foo.name)
}*/
Text(viewModel.foos[0].name).onTapGesture {
viewModel.selectedFoo = viewModel.foos[0]
}
Text(viewModel.foos[1].name).onTapGesture {
viewModel.selectedFoo = viewModel.foos[1]
}
})
}
}
}
final class MainViewModel: ObservableObject {
@ObservedObject var fooGroupViewModel: FooGroupViewModel
@Published var currentFoo: Foo?
init() {
fooGroupViewModel = FooGroupViewModel(foos: [Foo(name: "foo1", id: "1"), Foo(name: "foo2", id: "2")])
currentFoo = self.fooGroupViewModel.selectedFoo
}
}
struct MainView: View {
@ObservedObject var viewModel = MainViewModel()
var body: some View {
VStack {
FooGroupView(viewModel: viewModel.fooGroupViewModel)
.background(Color.red)
Spacer()
Text("Current:\(viewModel.currentFoo!.name)")
}.frame(width: 200, height: 200)
}
}
PlaygroundPage.current.liveView = UIHostingController(rootView: MainView())
在MainViewModel
中如果currentFoo
有变化,那么UI应该更新。
当点击 foo1
或 foo2
时,FooGroupViewModel
中的 selectedFoo
已更新,然后 MainViewModel
中应该得到更改(如 @ObservedObject var fooGroupViewModel: FooGroupViewModel
)
我的问题是如何让currentFoo
知道fooGroupViewModel
中selectedFoo
的变化?我以为这条线可以观察 selectedFoo
的变化,如果有任何更新,则触发 currentFoo
变化并更新 UI.
currentFoo = self.fooGroupViewModel.selectedFoo
但实际上是行不通的
有什么帮助吗?谢谢!
我还有一个问题,就是上面代码中的注释(如果将我的代码粘贴到Playground中,第56行)
ForEach(viewModel.foos) { foo in
Text(foo.name)
}
此代码使 playground 错误:
// Error: error: Execution was interrupted, reason: signal SIGABRT.
//The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
控制台中没有任何其他信息。不知道为什么。感谢您的帮助。
只做 currentFoo = self.fooGroupViewModel.selectedFoo
绝对行不通 - 它只是将 selectedFoo
当时的内容分配给 currentFoo
。
根据您的设置,您需要订阅 fooGroupViewModel.selectedFoo
中的更改,这可以通过 Published
发布者完成,因为它是 @Published
属性 .
此外,请记住 @ObservedObject
仅在视图内部有意义,因此我将其删除。
import Combine
// ...
final class MainViewModel: ObservableObject {
var fooGroupViewModel: FooGroupViewModel
@Published var currentFoo: Foo?
private var cancellables: Set<AnyCancellable> = []
init() {
fooGroupViewModel = FooGroupViewModel(foos:
[Foo(name: "foo1", id: "1"), Foo(name: "foo2", id: "2")])
fooGroupViewModel.$selectedFoo
.assign(to: \.currentFoo, on: self)
.store(in: &cancellables)
}
}