Ios 防止SwiftUI重置@State

Ios 防止SwiftUI重置@State,ios,swift,swiftui,Ios,Swift,Swiftui,我常常不理解SwiftUI何时重置视图的状态(即所有标记为@state的视图)。例如,请看下面的示例: import SwiftUI struct ContentView: View { @State private var isView1Active = true let view1 = View1() let view2 = View2() var body: some View { VStack { if isVi

我常常不理解SwiftUI何时重置视图的状态(即所有标记为@state的视图)。例如,请看下面的示例:

import SwiftUI

struct ContentView: View {
    @State private var isView1Active = true
    let view1 = View1()
    let view2 = View2()

    var body: some View {
        VStack {
            if isView1Active {
                view1
            } else {
                view2
            }

            Button(action: {
                self.isView1Active.toggle()
            }, label: {
                Text("TAP")
            })
        }
    }
}

struct View1: View {
    @State private var text = ""
    var body: some View {
        TextField("View1: type something...", text: $text)
    }
}

struct View2: View {
    @State private var text = ""
    var body: some View {
        TextField("View2: type something...", text: $text)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
我希望这两个
TextField
保留它们的内容,但如果运行此示例,会出现一些奇怪的行为:

  • 如果在预览中运行示例,则只有
    视图1
    文本字段
    内容仍然存在:

  • 相反,如果您在模拟器上运行示例(或在实际设备上运行),则第一个文本字段内容和第二个文本字段内容都不会保留:


那么,这里发生了什么?有没有办法告诉SwiftUI不要为视图重置@State?谢谢。

问题是每次更改
isView1Active
时都会重新创建
View1
View2
(因为它使用的是
@State
重新加载
ContentView
的主体)

解决方案是在
ContentView
中保留
TextField
的文本属性,如下所示,并使用
@Binding

struct ContentView: View {

    @State private var isView1Active = true
    @State private var view1Text = ""
    @State private var view2Text = ""

    var body: some View {
        VStack {
            if isView1Active {
                View1(text: $view1Text)
            } else {
                View2(text: $view2Text)
            }

            Button(action: {
                self.isView1Active.toggle()
            }, label: {
                Text("TAP")
            })
        }
    }
}

struct View1: View {

    @Binding var text: String

    var body: some View {
        TextField("View1: type something...", text: $text)
    }
}

struct View2: View {

    @Binding var text: String

    var body: some View {
        TextField("View2: type something...", text: $text)
    }
}

在行动中显示:


view1
view2
是完全独立和封闭的,就像没有
contextmenu
sheet
一样,您可以使用
ZStack
opacity
组合

 var body: some View {
    VStack {
        ZStack{
        if isView1Active {
            view1.opacity(1)
             view2.opacity(0)
        } else {
            view1.opacity(0)
            view2.opacity(1)

        }}

        Button(action: {
            self.isView1Active.toggle()
        }, label: {
            Text("TAP")
        })
    }
}

对于持久性,请使用外部视图模型(例如,ObservableObject)Hi@Asperi,谢谢。我知道使用ObserveObject是可行的,我很可能会这么做(即使我真的很想理解为什么SwiftUI会重置问题示例中的(at)状态)。我认为关于(at)状态管理,我们这里缺少了一些东西。
@State
只有在视图层次结构中查看时才有效。从
@State
的角度来看,您创建
View1
View2
的方式无效,因此您要观察您观察到的问题。实际上,如果将
View1
&
View2
直接放置在使用
View1
&
View2
变量的位置,您也会观察到同样的情况,因为
@State
仅在视图处于视图层次结构时才起作用。好吧,看来我的问题的实际答案是“
@State
只有在视图内部视图层次结构中才有效”,这很令人伤心,因为它有一些重要的含义。嗨,乔治,谢谢你。不幸的是,你说的是错的。在我的示例中,
View1
View2
不是每次都重新创建的,因为它们是主视图的
let
属性(您可以通过实现它们的
init()
方法轻松地对其进行测试。您将看到只调用了一次)。这正是我在问题中提出的问题。尽管视图与视图完全相同(未重新创建),但@State会以某种方式重置。SwiftUI何时重置@State变量?为什么?有办法控制它吗?@superpuccio我明白你的意思,我不知道为什么。但这看起来还是解决了你的问题。@superpuccio,George_E有正确的答案。@状态变量不会在呈现之间持久化。因此,即使您的内存中可能有@State,当视图从视图堆栈中移除时,这些状态变量也会重置。您必须使用@Binding。