问题描述
每次@ObservedObject
被重新分配"时,我想重设一些@State
.如何做到这一点?
I would like to reset some @State
each time an @ObservedObject
is "reassigned". How can this be accomplished?
class Selection: ObservableObject {
let id = UUID()
}
struct ContentView: View {
@State var selectedIndex: Int = 0
var selections: [Selection] = [Selection(), Selection(), Selection()]
var body: some View {
VStack {
// Assume the user can select something so selectedIndex changes all the time
// SwiftUI will just keep updating the same presentation layer with new data
Button("Next") {
self.selectedIndex += 1
if self.selectedIndex >= self.selections.count {
self.selectedIndex = 0
}
}
SelectionDisplayer(selection: self.selections[self.selectedIndex])
}
}
}
struct SelectionDisplayer: View {
@ObservedObject var selection: Selection {
didSet { // Wish there were something *like* this
print("will never happen")
self.tabIndex = 0
}
}
@State var tapCount: Int = 0 // Reset this to 0 when `selection` changes from one object to another
var body: some View {
Text(self.selection.id.description)
.onReceive(self.selection.objectWillChange) {
print("will never happen")
}
Button("Tap Count: \(self.tapCount)") {
self.tapCount += 1
}
}
}
我知道了onReceive
,但是我不是想响应objectWillChange
来修改状态,而是当对象本身被关闭时.在具有引用类型的UIKit中,我将使用didSet
,但这在这里不起作用.
I'm aware of onReceive
but I'm not looking to modify state in response to objectWillChange
but rather when the object itself is switched out. In UIKit with reference types I would use didSet
but that doesn't work here.
我确实尝试为此使用PreferenceKey
(要点),但看起来像太多了.
I did try using a PreferenceKey
for this (gist) but it seems like too much of a hack.
推荐答案
当前(测试版5),最好的方法可能是对数据要更改时要重置的项目使用构造函数以及通用的ObservableObject
.这样可以保留一些@State
,而有些则被重置.
Currently (Beta 5), the best way may be to use the constructor plus a generic ObservableObject
for items that I want to reset when the data changes. This allows some @State
to be preserved, while some is reset.
在下面的示例中,每次selection
更改时,tapCount
都会重置,而allTimeTaps
不变.
In the example below, tapCount
is reset each time selection
changes, while allTimeTaps
is not.
class StateHolder<Value>: ObservableObject {
@Published var value: Value
init(value: Value) {
self.value = value
}
}
struct ContentView: View {
@State var selectedIndex: Int = 0
var selections: [Selection] = [Selection(), Selection(), Selection()]
var body: some View {
VStack {
// Assume the user can select something so selectedIndex changes all the time
// SwiftUI will just keep updating the same presentation though
Button("Next") {
self.selectedIndex += 1
if self.selectedIndex >= self.selections.count {
self.selectedIndex = 0
}
}
SelectionDisplayer(selection: self.selections[self.selectedIndex])
}
}
}
struct SelectionDisplayer: View {
struct SelectionState {
var tapCount: Int = 0
}
@ObservedObject var selection: Selection
@ObservedObject var stateHolder: StateHolder<SelectionState>
@State var allTimeTaps: Int = 0
init(selection: Selection) {
let state = SelectionState()
self.stateHolder = StateHolder(value: state)
self.selection = selection
}
var body: some View {
VStack {
Text(self.selection.id.description)
Text("All Time Taps: \(self.allTimeTaps)")
Text("Tap Count: \(self.stateHolder.value.tapCount)")
Button("Tap") {
self.stateHolder.value.tapCount += 1
self.allTimeTaps += 1
}
}
}
}
在寻找解决方案时,我很感兴趣地发现您无法在init
中初始化@State
变量.编译器会抱怨在访问self之前尚未设置所有属性.
While looking for a solution I was quite interested to discover that you cannot initialize @State
variables in init
. The compiler will complain that all properties have not yet been set before accessing self.
这篇关于在SwiftUI中更新其他变量时如何修改/重置@State的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!