Pieter
Pieter

Reputation: 187

How to manage global state in SwiftUI and persist it

Continuing learning SwiftUI (which is so much fun) I'm doubting the way I'm managing (and storing) global state in my app and storing it. There are two categories of data that I need to manage. The first is an object from a third party library, it contains the logged in state of the user and the tokens to access the API. The second is some data that will be required for almost all API requests like the chosen server, the user's ID, and one or two other tidbits.

My current solution

The two categories of data each have a class to represent them, one, OIDAuthState, is from the third-party library I'm using. The other, Profile, is a class I've written. Both classes are Codable so they can be stored.

class Profile: Codable {
    var serverURL: String?
    var userID: String?
    // A few more fields all optional
}

I'm using a model class, AuthModel as an environment object which holds both data classes so I have access to the data everywhere in my app.

class AuthModel: ObservableObject {
    var authState: OIDAuthState?
    @Published var profile: Profile?
    @Published var isAuthenticated = false

    func login() async {
        // Perform login, if successful get an OIDAuthState instance from the third-party library
        self.authState = authState
        self.isAuthenticated = authState?.isAuthorized == true
    }
}

In the entry point I initialize the AuthModel and pass it to the root view that is displayed. That way I have access to the data in all my views.

@main
struct MyApp: App {
    @StateObject private var authModel = AuthModel()

    var body: some Scene {
        WindowGroup {
            if authModel.isAuthenticated {
                ContentView().environmentObject(authModel)
            } else {
                LoginFlowView().environmentObject(authModel)
            }
        }
    }
}

Most of my doubts come from my Profile class. All fields are added at different moments during login, so they are all optional. This causes a lot of optional unwrapping/chaining making the code ugly. Additionally, the data from the Profile class is mostly used to make API requests, I get it from the environment in my views and pass it as input to my models that make the requests. Going through the views feels as an unnecessary step.

Both the OIDAuthState and Profile will be saved so users remain logged in between app sessions, but I haven't figured out how or when to write them.

Upvotes: 0

Views: 166

Answers (0)

Related Questions