AliSoftware/Dip

Issues with modules' collaboration (Dip 5.0.2)

Closed this issue · 4 comments

Hi, @ilyapuchka !
We are using latest Dip version 5.0.2, modules and auto-injection.
We are trying to understand modules' collaboration but nothing works as we expected.

Here the code of DipRoot.swift:

import Dip

//
// 1 ATTEMPT
// Fails with error:
// Failed to auto-inject property "_settingsWireframe" of type SettingsWireframe.
// No definition registered for type: SettingsWireframe, arguments: (), tag: nil.
//
let dipRoot = DependencyContainer() { root in
  Dip.logLevel = .Verbose

  mainModule.collaborate(
    with: root,
    settingsModule
  )

  settingsModule.collaborate(
    with: root,
    mainModule
  )
}

let mainModule = DependencyContainer() { container in
  let mainWireframe = container.register(.singleton) {
    MainWireframe()
      as MainWireframe
  }

  let mainViewController = container.register(.weakSingleton) {
    MainViewController(nibName: "MainViewController", bundle: nil)
      as MainViewController
  }
}

let settingsModule = DependencyContainer() { container in
  let settingsWireframe = container.register(.singleton) {
    SettingsWireframe()
      as SettingsWireframe
  }
}


//
// 2 ATTEMPT
// Works:
//
let mainModule = DependencyContainer() { container in
  Dip.logLevel = .Verbose

  let mainWireframe = container.register(.singleton) {
    MainWireframe()
      as MainWireframe
  }

  let mainViewController = container.register(.weakSingleton) {
    MainViewController(nibName: "MainViewController", bundle: nil)
      as MainViewController
  }

  let settingsWireframe = container.register(.singleton) {
    SettingsWireframe()
      as SettingsWireframe
  }
}

Here the code of Wireframes.swift:

class MainWireframe {
  fileprivate let _settingsWireframe = Injected<SettingsWireframe>()
  var settingsWireframe: SettingsWireframe? { return _settingsWireframe.value }
}

class SettingsWireframe {
}

Here the code of AppDelegate.swift:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    window = UIWindow(frame: UIScreen.main.bounds)
    if let window = window {
      let vc = try! mainModule.resolve() as MainViewController
      let navigation = UINavigationController()
      window.rootViewController = navigation
      navigation.isNavigationBarHidden = true
      navigation.viewControllers = [vc]

      window.backgroundColor = UIColor.white
      window.makeKeyAndVisible()
    }

    return true
  }
}

Full error log here:

Failed to auto-inject property "_mainWireframe" of type MainWireframe.
Failed to auto-inject property "_settingsWireframe" of type SettingsWireframe.
No definition registered for type: SettingsWireframe, arguments: (), tag: nil.
Check the tag, type you try to resolve, number, order and types of runtime
arguments passed to `resolve()` and match them with registered factories
for type SettingsWireframe.
fatal error: 'try!' expression unexpectedly raised an error: Failed to auto-inject
property "_mainWireframe" of type MainWireframe.
Failed to auto-inject property "_settingsWireframe" of type SettingsWireframe.
No definition registered for type: SettingsWireframe, arguments: (), tag: nil.
Check the tag, type you try to resolve, number, order and types of runtime
arguments passed to `resolve()` and match them with registered factories
for type SettingsWireframe.:
file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-800.0.46.2/src/swift/stdlib/public/core/ErrorType.swift, line 178

Here is the test project with .Podfile:
dipCollaborationIssuePackage.zip

Workaround is clear for us.
Do not use modules' collaboration.
Split the dependencies into several functions for purpose of clarity.

let dipRoot = DependencyContainer() { container in
  Dip.logLevel = .Verbose

  registerMyModuleName(container: container)
}

func registerMyModuleName(container: DependencyContainer) {
  ... register dependencies
}

Hi @sc0rch. The problem may be that your containers are actually never created, except main container. In Swift global static constants are lazy. Here it says:
"The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic. "
And as you have collaboration setup in root container that is never accessed this code is never executed. I would probably create a configure method that would be called from app delegate and that sets up collaboration what will make it to accesses all containers.

Oh, I see. I haven't knew about that.
Thanks for the help, problem has been fixed.