SwiftUI 如何将@Published 分配给另一个@Published
Posted
技术标签:
【中文标题】SwiftUI 如何将@Published 分配给另一个@Published【英文标题】:SwiftUI How to assign @Published to another @Published 【发布时间】:2020-10-24 04:20:46 【问题描述】:我有一个视图(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
知道selectedFoo
在fooGroupViewModel
中的变化?我原以为这条线可以观察到selectedFoo
的变化,如果有任何更新则触发currentFoo
的变化并更新UI。
currentFoo = self.fooGroupViewModel.selectedFoo
但实际上它不起作用。
有什么帮助吗?谢谢!
我还有另一个问题,上面代码中的注释(如果将我的代码粘贴到 Playground 则为第 56 行)
ForEach(viewModel.foos) foo in
Text(foo.name)
这段代码使操场出错:
// 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.
控制台中没有任何其他信息。不知道为什么。感谢您的帮助。
【问题讨论】:
【参考方案1】:只做currentFoo = self.fooGroupViewModel.selectedFoo
肯定是行不通的——它只是将currentFoo
分配给当时selectedFoo
的任何值。
通过您的设置,您需要订阅fooGroupViewModel.selectedFoo
中的更改,这可以通过Published
发布者完成,因为它是@Published
属性。
另外,请记住 @ObservedObject
仅在 View 中有意义,因此我将其删除。
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)
【讨论】:
非常感谢,刚刚将cancellables
更改为&cancellables
完美!以上是关于SwiftUI 如何将@Published 分配给另一个@Published的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 和具有 @Published 的组合 Observable 对象不断发布
如何将我的 SwiftUI 视图的 @State 交换为我的视图模型 @Published 变量?
如何检测 SwiftUI 中的 @Published 值发生了啥变化?
SwiftUI:如何使用 UserDefaults 持久化 @Published 变量?