1

// I am trying to pass in the value of the @AppStorage onto the class using @Binding. // Declaration of @AppStorge, this the the single source of truth. // I get the following error on the SigninViewModel = Class 'SigninViewModel' has no initializers

    import SwiftUI
    
    struct MainView: View {
        @AppStorage("userSignIn") var userSignIn = false
    
        var body: some View {
            ZStack {
                TabView {
                    AppointmentsView()
                        .tabItem {
                            Image(systemName: "calendar")
                            Text("Appointments")
                        }
                    
                    AccountView(userSignIn: .constant(true))
                        .tabItem {
                            Image(systemName: "person")
                            Text("Profile")
                        }
                    
                    StatsView()
                        .tabItem {
                            Image(systemName: "chart.bar")
                            Text("Stats")
                        }
                }
            }
        }
    }
    
    

// This the class with the @Binding is being declared and where I am trying to have access to the @AppStorae value.

    class SigninViewModel: ObservableObject {
        @Published var nonce = ""
        @Binding var userSignIn: Bool
    
        
        func authenticate(credential: ASAuthorizationAppleIDCredential) {
            
            // getting Token...
            guard let token = credential.identityToken else {
                print("Error with Firebase")
                return
            }
            
            //Token String...
            guard let tokenString = String(data: token, encoding: .utf8) else {
                print("Error with Token")
                return
            }
            
            let firebaseCredential = OAuthProvider.credential(withProviderID: "apple.com",
                                                              idToken: tokenString,
                                                              rawNonce: nonce)
            
            Auth.auth().signIn(with: firebaseCredential) { (result, err) in
                if let error = err {
                    print(error.localizedDescription)
                    return
                }
                
                // User succesfully logged into Firebase...
                print("Logged in Success")
                            
                
                // Directing user to Main page...
                withAnimation(.easeInOut) {
                    self.userSignIn = true
                }
            }
        }
    }
JLico
  • 27
  • 1
  • 7
  • Does this answer the question? https://stackoverflow.com/questions/64117138/how-do-you-access-edit-an-appstorage-var-from-multiple-other-views-in-swiftui – nickreps Jan 09 '22 at 17:13

1 Answers1

2

You can put the @AppStorage("userSignIn") inside the ObservableObject, but your code quickly becomes a mess.

I think a more simple structure would be to put all of your authentication state inside a single AuthenticationModel: ObservableObject and use it as a @StateObject in the MainView. Additionally, I would recommend pushing it up the view tree.

class AuthenticationModel: ObservableObject {
    @Published var nonce = ""
    @Published var userSignIn: Bool

    init() {
        let defaults = UserDefaults.standard
        userSignIn = defaults.bool(forKey: "userSignIn")
    }

    func authenticate(credential: ASAuthorizationAppleIDCredential)
        ...

        // Successful Login
        let defaults = UserDefaults.standard
        defaults.set(true, forKey: "userSignIn")
        
        // Update the views
        userSignIn = true
    }
}


struct MainView: View {
    @StateObject var authModel: AuthenticationModel = AuthenticationModel()

    var body: some View {
        if authModel.userSignIn {
            Home(authModel: authModel)
        } else {
            SignIn(authModel: authModel)
        }
    }
}


struct SignIn: View {
    @ObservedObject var authModel: AuthenticationModel

    var body: some View {
        Button("Sign In") {
            authModel.authenticate(...)
        }
    }
}
Adam Comer
  • 492
  • 2
  • 10