2

I'm trying to re create an older version of my Onboarding setup with the new SwiftUI and when I try to share the state so the view changes, it simply doesn't know that something has changed, this is what I'm doing:

In the main .swift struct (not ContentView.swift) I defined the pages like this:

@main
struct AnotherAPP: App {
    
    @ObservedObject var onBoardingUserDefaults = OnBoardingUserDefaults()
    
    let persistenceController = PersistenceController.shared
    
    var body: some Scene {
        WindowGroup {
            // Onboarding screen
            if (onBoardingUserDefaults.isOnBoardingDone == false) {
                OnboardingPageView()
            } else {
                UserLoginView()
            }
        }
    }
}

So on the onBoarding page when I click the button to go to the login, it stores it, but it doesn't actually refreshes the view. There (in the OnboardingPageView.swift) I call the UserDefaults like this:

@ObservedObject private var onBoardingUserDefaults = OnBoardingUserDefaults()

and on the button I change it like this:

self.onBoardingUserDefaults.isOnBoardingDone = true
UserDefaults.standard.synchronize()

So what's going on?

I know for instance if I create a @State on the @main and I bind it to the OnboardingPageView it works, as soon as I hit that button it takes me there.

ElKePoN
  • 822
  • 11
  • 21

2 Answers2

3

You can use AppStorage to manage UserDefaults variable in multiple views:

@main
struct TestApp: App {
    @AppStorage("isOnBoardingDone") var isOnBoardingDone = false
    
    var body: some Scene {
        WindowGroup {
            if !isOnBoardingDone {
                OnboardingPageView(isOnBoardingDone: $isOnBoardingDone)
            } else {
                UserLoginView()
            }
        }
    }
}

struct OnboardingPageView: View {
    @Binding var isOnBoardingDone: Bool

    var body: some View {
        Button("Complete") {
            isOnBoardingDone = true
        }
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
  • That worked very well, thanks. I was unaware of the new `@AppStorage`. How would I read the value from that on another view? Would it be: `UserDefaults.standard.bool(forKey: "isOnBoardingDone") == false`? – ElKePoN Oct 12 '20 at 14:50
  • @Arturo `AppStorage` is just a wrapper on top of `UserDefaults` (that still can be accessed in a *normal* way). You can read more here: [What is @AppStorage property wrapper](https://stackoverflow.com/a/62563773/8697793) – pawello2222 Oct 12 '20 at 14:52
1

If I understood correctly, you are trying to pass the value of a state variable in the Content View to another view in the same app. For simplicity, Let's say your variable is initialised as follows in ContentView:

@State private var countryIndex = 0 //Assuming the name of the variable is countryIndex  

Now, to transfer the value write the following in the Content View (or wherever the variable is initially):

//Other code 

NavigationLink(destination: NextPage(valueFromContentView: $countryIndex)) {
                                Text("Moving On")
                  }//In this case, the variable that will store the value of countryIndex in the other view is called valueFromContentView

//Close your VStacks and your body and content view with a '}' 

In your second view or the other view, initialise a Binding variable called valueFromContentView using:

@Binding var valueFromContentView: Int

Then, scroll down to the code that creates your previews. FYI, It is another struct called ViewName_Previews: PreviewProvider { ... }

IF you haven't changed anything, it will be:

struct NextPage_Previews: PreviewProvider {
    static var previews: some View {
       
    }
}

Remember, my second view is called NextPage.

Inside the previews braces, enter the code:

 NextPage(valueFromContentView: .constant(0))

So, the code that creates the preview for your application now looks like:

struct NextPage_Previews: PreviewProvider {
    static var previews: some View {
        NextPage(valueFromContentView: .constant(0)) //This is what you add
    }
}

Remember, NextPage is the name of my view and valueFromContentView is teh binding variable that I initialised above

Like this, you now can transfer the value of a variable in one view to another view.