iosswiftswinject

Dependency injection inconsistency in differing ViewControllers in Swinject, post Swift 3.0 update: why?


I am registering some Swinject singleton-with-a-small-s (.container) services thus:

defaultContainer.register( SomeService.self )
{
    _ in SomeService() 
}.inObjectScope( .container )

defaultContainer.register( AnotherService.self )
{
    responder in AnotherService(
        someService: responder.resolve( SomeService.self )!
    )
}.inObjectScope( .container )

Injecting them into some view controllers thus:

defaultContainer.registerForStoryboard( SomeViewController.self )
{
    resolvable, viewController in
    viewController.someService = resolvable.resolve( SomeService.self )
    viewController.anotherService = resolvable.resolve( AnotherService.self )!
}

defaultContainer.registerForStoryboard( AnotherViewController.self )
{
    resolvable, viewController in
    viewController.someService = resolvable.resolve( SomeService.self )
    viewController.anotherService = resolvable.resolve( AnotherService.self )!
}

These view controllers are then being displayed in two different ways, SomeViewController like this:

DispatchQueue.main.async
{
    self.performSegue( withIdentifier: "somePageSegue", sender: nil )
}

And AnotherViewController like this:

let anotherViewController = UIStoryboard(
    name: "Main"
    , bundle: nil
).instantiateViewController( withIdentifier: "anotherSegue" )

present( anotherViewController, animated: true, completion: nil )

SomeViewController gets its services injected, but unfortunately AnotherViewController does not.

This used to work prior to Swinject's upgrade to Swift 3.0, but does not now. Why is this, and what needs to be changed, please?

Thank you.

UPDATE

I have neither the familiarity with Swinject's underlying code base nor the time to familiarize myself unfortunately, but digging around with what is happening under the surface I have discovered the following, which is hopefully useful to anyone who might know it better than I:

SUCCESSFUL VC DI:

// once into:
private func injectDependency(to viewController: UIViewController)

// then:
defaultContainer.registerForStoryboard( SomeViewController.self )

// then many times into:
public func _resolve<Service, Factory>(name: String?, option: ServiceKeyOptionType? = nil, invoker: (Factory) -> Service) -> Service?

FAILED VC DI:

// repeatedly going from:
private func injectDependency(to viewController: UIViewController)

// to:
public func _resolve<Service, Factory>(name: String?, option: ServiceKeyOptionType? = nil, invoker: (Factory) -> Service) -> Service?

// and back again,
// then twice into:
public override func instantiateViewController(withIdentifier identifier: String) -> UIViewController

ADDITIONAL NOTES:

The failing VC is a UIViewController within a TabBarController, both of which are already laid out in a standard XCode storyboard.


Solution

  • It turns out this is a bug, detailed here: https://github.com/Swinject/Swinject/issues/177. A fix is currently being worked on. I will report back once I know more.

    UPDATE

    This is apparently fixed.