How to update variable proper in different struct Swift

只谈情不闲聊 提交于 2020-05-17 07:07:13

问题


In the code below, the variable "yourVariable" is defined in a struct. Then I use a slider to change the "yourVariable" but when I try and use the variable in the SecondView, it uses the original variable and not the updated one. I have been told I need to update the property, should I do this? If yes can someone please explain why.

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())

回答1:


First off, the slider is updating the variable slidetwo witch has an initial value of 560000.

When you open the second view you are getting the value of the struct into the variable string witch will result in having always the value that's defined by yourVariable, so moving the slider does not affect at all the second view.

In order to properly do this you could use a Binding in case that you want the variable to be changed inside the second view and reflecting those changes in the ContentView or a simple un-initialized @State var

Going with the second option it would result in replacing, in the SecondView var string = MyVariables.yourVariable with @State var string: String

Then in the ContentView inside the sheet you call SecondView(string: String(slidetwo)) instead of SecondView()

I couldn't figure out why would you need a struct in here. All it does is hold a default value and nothing more, and you don't update the variable anywhere. You can't update it directly because it can't be binded.

Update 1:

Based on your comment, what I understand is that you want multiple variables to the SecondView, if that's the case you are better off using and ObservableObject in conjunction of EnvironmentObject

And it's rather easy to do. First create a class that will hold all your variables. This class inherits from the 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
    }
}

Now on the first view you want to initialize the class and use it where you need it. At this point the slide two will not update the @State variable, but the variable in the model, and we will need to pass the ObservedObject to the second view like so.

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
    }
}

Now we are sending the model with the data updated on the first view, to the second view, and any changes will be reflected in both views, just one last thing, capture this EnvironmentObject on the second view

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

In this case the model.yourVariable still doesn't change because we are updating the model.slidertwo variable. Changes made to the model will be reflected in both views.

From the experience that I have this is the correct way to do things in SwiftUI




回答2:


I'm afraid I'm too late but what you could also adjust in your code is to change the slideTwo variable to.

@Binding public var slidetwo: Double

You'd have to do the +60000 addition in the struct directly and then initialize your view as follows:

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

That would result in applying all changes to slideTwo to be applied to yourVariable as well. However, as Pedro already mentioned, I wouldn't recommend that approach with the struct.



来源:https://stackoverflow.com/questions/61739670/how-to-update-variable-proper-in-different-struct-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!