概述
- 我有一辆
@StateObject
,它被用来开一辆NavigationSplitView
. - 我使用
@StateObject
上的@Published
个属性来驱动视图的 Select .一百零二 - 当我进入
NavigationSplitView
人的最终 Select 时,我想创造一个Selection
分. - 这应该会发布一个属性only once.
import SwiftUI
import Combine
struct Consumption: Identifiable, Hashable {
var id: UUID = UUID()
var name: String
}
struct Frequency: Identifiable, Hashable {
var id: UUID = UUID()
var name: String
}
struct Selection: Identifiable {
var id: UUID = UUID()
var consumption: Consumption
var frequency: Frequency
}
class SomeModel: ObservableObject {
let consump: [Consumption] = ["Coffee","Tea","Beer"].map { str in Consumption(name: str)}
let freq: [Frequency] = ["daily","weekly","monthly"].map { str in Frequency(name: str)}
@Published var consumption: Consumption?
@Published var frequency: Frequency?
@Published var selection: Selection?
private var cancellable = Set<AnyCancellable>()
init(consumption: Consumption? = nil, frequency: Frequency? = nil, selection: Selection? = nil) {
self.consumption = consumption
self.frequency = frequency
self.selection = selection
$frequency
.print()
.sink { newValue in
if let newValue = newValue {
print("THIS SHOULD APPEAR ONCE")
print("---------------")
self.selection = .init(consumption: self.consumption!, frequency: newValue)
} else {
print("NOTHING")
print("---------------")
}
}.store(in: &cancellable)
}
}
问题
视图上的@StateObject
是发布property twice的.(请参阅下面的代码)
struct ContentView: View {
@StateObject var model: SomeModel = .init()
var body: some View {
NavigationSplitView {
VStack {
List(model.consump, selection: $model.consumption) { item in
NavigationLink(value: item) {
Label(item.name, systemImage: "circle.fill")
}
}
}
} content: {
switch model.consumption {
case .none:
Text("nothing")
case .some(let consumption):
List(model.freq, id:\.id, selection: $model.frequency) { item in
NavigationLink(item.name, value: item)
}
.navigationTitle(consumption.name)
}
} detail: {
switch model.selection {
case .none:
Text("nothing selected")
case .some(let selection):
VStack {
Text(selection.consumption.name)
Text(selection.frequency.name)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我的解决方案
如果我通过在视图上创建@State
个属性来更改视图,然后使用OnChange
修改器更新模型,我会将属性设置为update once.这就是我想要的.(请参阅下面的代码)
struct ContentView: View {
@StateObject var model: SomeModel = .init()
@State private var consumption: Consumption?
@State private var frequency: Frequency?
var body: some View {
NavigationSplitView {
VStack {
List(model.consump, selection: $consumption) { item in
NavigationLink(value: item) {
Label(item.name, systemImage: "circle.fill")
}
}
}.onChange(of: consumption) { newValue in
self.model.consumption = newValue
}
} content: {
switch model.consumption {
case .none:
Text("nothing")
case .some(let consumption):
List(model.freq, id:\.id, selection: $frequency) { item in
NavigationLink(item.name, value: item)
}
.navigationTitle(consumption.name)
.onChange(of: frequency) { newValue in
self.model.frequency = newValue
}
}
} detail: {
switch model.selection {
case .none:
Text("nothing selected")
case .some(let selection):
VStack {
Text(selection.consumption.name)
Text(selection.frequency.name)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
问题/帮助
在@StateObject + @Published
和View + @State
之间,@Binding
的行为有区别吗?
我不明白为什么在我之前的视图中,该属性被发布了两次.
我的解决方案需要做更多的工作,但它通过使用@State
和onChange
个视图修饰符来工作.