hmlongco / Factory

A new approach to Container-Based Dependency Injection for Swift and SwiftUI.
MIT License
1.71k stars 107 forks source link

Resetting scopes #139

Closed totidev closed 11 months ago

totidev commented 11 months ago

Is there a way to reset a Factory to its original state, or to change the current value, until it is reset?

I am looking at the example provided here, showing an authenticatedUser.

What if the user logging in was not a standard AuthenticatedUser, but instead an AdminUser? If I were to register a new implementation for this type of user, when I reset the scope, it would not default back to being an AuthenticatedUser, but it would instead maintain the new factory I had registered, which is an AdminUser.

I realise of course that I could just change the logic to register either type, based on the type of login. But here is another example: what if the AuthenticatedUser needed to store a sessionId for the duration of the session? Should I even be using Factory for this, or should I hold the sessionId in another place?

Alternatively, would it be possible for Factory to support a set function? Where the currently stored item can be set, but if you reset this, it is returned to its original default state? Assuming the implementation of AuthenticatedUser was:

struct AuthenticatedUser {
    var sessionId: Int? = nil
}

In this case, sessionId may be returned from a server, so it would not be possible to create it upfront with a sessionId. By having the set function, we could call something like:

Container.shared.authenticatedUser.set(AuthenticatedUser(sessionId: 123))

And any time the authenticatedUser is requested, the new value with sessionId 123 is returned, until the session scope is reset, in which case it would revert to being a nil sessionId.

hmlongco commented 11 months ago

You're getting to the point where I might consider simply creating a Session container.

final class Session: SharedContainer {
    static let shared = Session()
    var id: Factory<String?> {
        self { nil } .cached
    }
    var authenticatedUser: Factory<AuthenticatedUserType?> {
        self { nil } .cached
    }
    // whatever else is needed
    let manager = ContainerManager()
}

func login(id: Int, admin: Bool) {
    Session.shared.id.register { id }
    Session.shared. authenticatedUser.register {
        admin ? AdminUser(id: id ) : RegularUser(id: id )
    }
}

func logout() {
    Session.shared.manager.reset()
}

Calling reset() on the container resets everything to to original state.

totidev commented 11 months ago

Thanks for the answer. Keeping data in a SessionContainer may be a better approach, as I can then just reset the entire container.