如何更新不同结构中的变量 Swift

How to update variable proper in different struct Swift

在下面的代码中,变量 "yourVariable" 是在结构中定义的。然后我使用滑块更改 "yourVariable" 但是当我尝试在 SecondView 中使用变量时,它使用原始变量而不是更新后的变量。我被告知我需要更新 属性,我应该这样做吗?如果是,有人可以解释原因吗。

import SwiftUI
import PlaygroundSupport

struct MyVariables {
    static var yourVariable = 500000.0
}



struct SecondView : View {
    @Environment(\.presentationMode) var presentationMode
    var string = MyVariables.yourVariable
    var body: some View {
        VStack {Button("\(string)") {
            self.presentationMode.wrappedValue.dismiss()
            } 
        }
    }
}


struct ContentView : View {
    @State private var showingSheet = false

    @State public var step = 0
    @State public var text = ""
    @State public var slide = 20.0
    @State public var slidetwo = MyVariables.yourVariable + 60000
    var r0 : Double {
        rvalues[(wearingMaskToggle ? 1:0) + (washingHandsToggle ? 2:0) + (quarantineToggle ? 8:0) + (coverMouthToggle ? 4:0)]
    }
    @State private var rvalues = [6.5, 6.1, 5.3, 4.8, 4.2, 3.5, 3.1, 2.9, 1.75, 1.5, 1.2, 1.0, 0.92, 0.82, 0.75, 0.7]

    var body: some View {
        ZStack {
            Color.gray
                .edgesIgnoringSafeArea(.all)
                VStack {
                    HStack {
                        Button(action: {
                            if self.slidetwo > 10000{
                                self.slidetwo -= 1000 //When rand = 10050, it still works
                            }
                        }, label: {
                            Image(systemName: "minus")
                        })
                        Slider(value: $slidetwo, in: 10000...1000000, step: 1000)
                            .padding(20)
                            .accentColor(Color.green)
                        Button(action: {
                            if self.slidetwo < 1000000{
                                self.slidetwo += 1000
                            }
                        }, label: {
                            Image(systemName: "plus")
                        })
                    }.foregroundColor(Color.green) .padding(.horizontal, 100)
                }
                Text("Initial Population: \(Int(slidetwo))")

                Button("Show Sheet") {
                    self.showingSheet.toggle()
                }
                .sheet(isPresented: $showingSheet) {
                    SecondView()
                }
            }
        }
}
PlaygroundPage.current.setLiveView(ContentView())

首先,滑块正在更新变量 slidetwo 的初始值为 560000

当您打开第二个视图时,您正在将结构的值放入变量 string 将导致始终具有 yourVariable 定义的值,因此移动滑块根本不影响第二个视图。

为了正确执行此操作,您可以使用 Binding 以防您希望在第二个视图中更改变量并将这些更改反映在 ContentView 或简单的 un-已初始化 @State var

使用第二个选项会导致在 SecondView var string = MyVariables.yourVariable 中用 @State var string: String

替换

然后在 sheet 里面的 ContentView 你调用 SecondView(string: String(slidetwo)) 而不是 SecondView()

我不明白为什么你需要一个结构在这里。它所做的只是保留一个默认值,仅此而已,您不会在任何地方更新变量。无法绑定,无法直接更新

更新 1:

根据您的评论,我的理解是您希望 SecondView 有多个变量,如果是这种情况,您最好将 ObservableObjectEnvironmentObject[=34= 结合使用]

而且这很容易做到。首先创建一个 class 来保存所有变量。此 class 继承自 ObservableObject

class MyVariables: ObservableObject {

    @Published var sliderTwo: Double = 0.0
    @Published var yourVariable = 500000.0 // <- I don't know the purpose of this

    init() {
        sliderTwo = yourVariable + 60000   // <- This is the original value, in the original code
    }
}

现在,在第一个视图中,您要初始化 class 并在需要的地方使用它。此时第二张幻灯片不会更新 @State 变量,而是更新模型中的变量,我们需要像这样将 ObservedObject 传递给第二个视图。

struct ContentView: View {
    @ObservedObject var model: MyVariables = MyVariables()
    //@State public var slidetwo = MyVariables.yourVariable + 60000 <- no longer needed
    // ... change every other reference of slidertwo to model.slidertwo
    // except the following one witch instead of $slidertwo it will be $model.slidertwo
    Slider(value: $model.slidertwo, in: 10000...1000000, step: 1000)
    // ...
    .sheet(isPresented: $showingSheet) {
        SecondView().environmentObject(self.model) // send the model as an environment object
    }
}

现在我们将在第一个视图上更新了数据的模型发送到第二个视图,任何更改都会反映在两个视图中,最后一件事,在第二个视图中捕获此 EnvironmentObject查看

struct SecondView: View {
    // var string = MyVariables.yourVariable <- no longer needed
    @EnvironmentObject var model: MyVariables
    // ....
}

在这种情况下,model.yourVariable 仍然没有改变,因为我们正在更新 model.slidertwo 变量。 对模型所做的更改将反映在两个视图中。

根据我的经验,这是在 SwiftUI 中做事的正确方法

恐怕我来不及了,但您还可以在代码中进行调整,将 slideTwo 变量更改为。

@Binding public var slidetwo: Double

您必须直接在结构中执行 +60000 加法,然后按如下方式初始化您的视图:

PlaygroundPage.current.setLiveView(ContentView(slidetwo: .init(get: { () -> Double in
    return MyVariables.yourVariable
}, set: { (newValue) in
    MyVariables.yourVariable = newValue
})))

这将导致将对 slideTwo 的所有更改也应用到 yourVariable。但是,正如 Pedro 已经提到的,我不建议使用结构的这种方法。