1

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
  • 2
    where are you changing the value of yourVariable ? Commented May 11, 2020 at 21:34

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

where do I put the @Binding? and how many variables can I use?
@EliasFizesan instead of @State public var slidetwo = MyVariables.yourVariable + 60000. But don't forget to initialize static var yourVariable with 560000.0 instead of 500000.0. The @Binding annotation allows you to "sync back" your changes to slideTwo, that means whenever you change this value, your MyVariables.yourVariable will also be updated due to the getter/setter I provided in the second code snippet of my answer.
I don't understand your question "and how many variables can I use?". You can you as many variables as you want.
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

21 Comments

Check the updated response, basically you use a class, that inherits from ObservableObject, all explained
Just a note, that I did not add on my response, some times if you want only two variables you can use two @Bindings, you could use as many as you want but then you would get a messy code, this way you can add as many variables as you want and still keep the code clean ;)
I can't help you more then this pastebin.com/gL4vh8rs and I don't like doing it, but as my response contains the exactly the same response but explained. I hope that at least you tried to understand it. The paste that I provided is the code of the question implemented with the ObservedObject and commented out your code that's no longer necessary. Also added two buttons in the second view to watch the ObservedObject in action
Did you check the paste that I provided? That paste Is working completely in the Playground
Can't help you more without seeing code. Maybe some thing that you forgot to change, I don't know, maybe the slider linked to the wrong variable
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.