Swinject / SwinjectStoryboard

Swinject extension for automatic dependency injection via Storyboard
MIT License
268 stars 141 forks source link

Registering storyboard view controller on a child container of "defaultContainer" #30

Closed alynmuntean closed 7 years ago

alynmuntean commented 7 years ago

Hello, so I have the following view controller class, which is actually my initial view controller in storyboard:

class RootViewController: UIViewController {
    var presenter: RootPresenter?
}

On the "SwinjectStoryboard" extension, I do the following:

class func setup() {
    let childContainer = Container(parent: defaultContainer)
        childContainer.registerForStoryboard(RootViewController.self) { (resolver, controller) in
            let presenter = resolver.resolve(RootPresenter.self)
            controller.presenter = presenter
        }
        childContainer.register(RootPresenter.self) { _ in
            RootPresenter()
        }
}

Resolver closures are never called, could you please help me understand why?

Note: When I register directly on "defaultContainer" (not on a child of it), it works ok.

Thank you in advance, Alin

marius-bardan commented 7 years ago

Is this an issue or is the lib being misused somehow?

yoichitgy commented 7 years ago

I think you need to pass childContainer to a initializer of SwinjectStoryboard.

marius-bardan commented 7 years ago

@yoichitgy could you be more specific, with an example? It would help.

From the swiftInject docs, what @alynmuntean posted should work - https://github.com/Swinject/Swinject/blob/master/Documentation/ContainerHierarchy.md .

yoichitgy commented 7 years ago

I think unit test code passing a container to SwinjectStoryboard can be an example.

yoichitgy commented 7 years ago

Only defaultContainer is automatically tied to SwinjectStoryboard. The other containers should be passed to SwinjectStoryboard manually.

marius-bardan commented 7 years ago

So the idea is to create a new SwinjectStoryboard, which basically means a new Storyboard object, each time we want to call 'registerForStoryboard' on a childContainer?

yoichitgy commented 7 years ago

I think it's each time you call a set of registerForStoryboard methods on a container if you don't use defaultContainer.

yoichitgy commented 7 years ago

I'm sorry that I couldn't take more time to see your comments and code. Currently Swinject project has too many things to do.

Would you let me know if the issue is resolved?

MathiasRoelants commented 7 years ago

You're trying to create a child container inside another container. This won't work as a parent doesn't resolve it's child(s) (docs: container hierarchy). By explicitly instantiating your storyboard you can pass your parent to your child. Which will then use your child instead of defaultContainer. If you want to, you can still use the SwinjectStoryboard extension for injection in your parent container. Injection in your child container will however have to be done somewhere else.

I had a similar issue for which I created a root configuration class which does root setup (plist reader, etc) and an app configuration class which resolves services, viewmodels, ..

let fooConfig = FooConfig()
let fooChildConfig = FooChildConfig(fooConfig.container) 
let storyboard = SwinjectStoryboard.create(name: "Main", bundle: nil, container: fooChildConfig.container)
window.rootViewController = storyboard.instantiateInitialViewController()
let fooConfig = FooConfig(Swinjectstoryboard.defaultContainer) 
let storyboard = SwinjectStoryboard.create(name: "Main", bundle: nil, container: fooConfig.container)
window.rootViewController = storyboard.instantiateInitialViewController()
yoichitgy commented 7 years ago

Thanks @MathiasRoelants for writing the details about SwinjectStoryboard with a custom container, and sharing your experience with the examples.

yoichitgy commented 7 years ago

@alynmuntean, did your question get clear?

alynmuntean commented 7 years ago

@yoichitgy Yes, sorry that I forgot to answer. @MathiasRoelants Thank you for the example!