hmlongco / Factory

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

Multiple previews and resolving different values for a singleton #150

Closed drekka closed 1 year ago

drekka commented 1 year ago

Been hurting my brain trying to figure out the best approach to this and hoping there's a simple solution I've just not thought of :-)

In a SwiftUI preview I have a number of previews I want to return with different values. For example (made up):

struct Hello_Preview: PreviewProvider {
static var previews: some View {
        Container.share.user.register { NoUser() }
        HelloView()
            .previewDisplayName("No user")
        Container.share.user.register { SubscribedUser() }
        HelloView()
            .previewDisplayName("Subscribed user")
    }

Now I'm sure you're about to tell me this won't work and it doesn't because both instances of HelloView resolve the user much later and get the same subscribed user.

I can't just pass the user in because as much as I'd like to, HelloView is a complicated view with many sub views in it and I'd end up writing a lot of boilerplate to pass the user down which would defeat the purpose of using Factory in the first place.

So my question is - is there a way to setup factory's user registration so that the correct user is returned when the factory resolves for a preview without having to change anything in the injections littered throughout the view hierarchy?

My currently (ugly) solution to all of this is to create multiple PreviewProvider structs instead of just one and that can become messing with a lot of cut-n-paste. So I'd really like just Ione :-)

hmlongco commented 1 year ago

First, check out the Multiple Previews section in the docs. https://hmlongco.github.io/Factory/documentation/factory/previews

doozMen commented 8 months ago

This happens because SwiftUI works in a tree and does not work only on init. The body happens later. This bit me too. See issue on scene specific factory results for a use case in a running app. So I think there should be a recommended way to deal with factory and environment combinations. Mine is just a suggestion but requires a rewrite of every view you made

doozMen commented 8 months ago

I have a case that does not work with the multiple preview as you describe

As body happens after init no matter what you do the child could potentially get a different service is in between init of content view and the body call the registration for service1 changes. To Solve it you would pass service1 in the body to The child on init. But that beets the purpose of using factory to inject.

So I'm a bit stuck with that.

hmlongco commented 8 months ago

Every instance of @Injected triggers s new factory resolution. Have you tried using a .shared scope?