Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I have same types with different values inside but of course DIP resolves the last one, which had been registered #226

Closed
montazher opened this issue Jul 18, 2019 · 3 comments
Labels

Comments

@montazher
Copy link

I dig dip into Dependency Injection in Swift via DIP and I faced some collision that I don't understand how to avoid properly. I have same types with different values inside but of course DIP resolves the last one, which had been registered. I'll explain you with code: Here is ViewController & ViewModel 1

final class ViewController1: UIViewController {

  @IBOutlet weak var label: UILabel!
  var viewModel: ViewModelA!

  override func viewDidLoad() {
    super.viewDidLoad()
    self.label.text = viewModel.value
  }

}

struct ViewModelA {
  typealias UseCases = ProtocolA
  let value: String

  init(useCases: UseCases) {
    self.value = useCases.value
  }
}

The second ViewController and ViewModel are the same except the different name. ViewController2 and ViewModelB. The Composition1 is

enum Composition1 {
  static func configure(_ container: DependencyContainer) {
    container.register {
      Data(value: "Composition1")
    }

    // Use Cases
    container.register { (data: Data) in
      data as ViewModelA.UseCases
    }

    // View Models
    container.register { useCases in
      ViewModelA(useCases: useCases)
    }

    // View Controller
    container
      .register(storyboardType: ViewController1.self, tag: "ViewController1")
      .resolvingProperties { container, controller in
        controller.viewModel = try container.resolve()
    }

    DependencyContainer.uiContainers.append(container)
  }
}

and the Composition2 is

enum Composition2 {
  static func configure(_ container: DependencyContainer) {
    container.register {
      Data(value: "Composition2")
    }

    // Use Cases
    container.register { (data: Data) in
      data as ViewModelB.UseCases
    }

    // View Models
    container.register { useCases in
      ViewModelB(useCases: useCases)
    }

    // View Controller
    container
      .register(storyboardType: ViewController2.self, tag: "ViewController2")
      .resolvingProperties { container, controller in
        controller.viewModel = try container.resolve()
    }

    DependencyContainer.uiContainers.append(container)
  }
}

The RootComposition is:

enum RootComposition {
  static func configure() -> DependencyContainer {
    let container = DependencyContainer()
    Composition1.configure(container)
    Composition2.configure(container)
    return container
  }
}

So all ViewControllers - the 1 and 2 show "Composition2" in the label because Composition2.configure called the last one. Could somebody give me a helping hand please? What is the proper way to register and reset container?

@ilyapuchka
Copy link
Collaborator

Generally different implementations of the same type are registered and resolved with tags. I'd also advice against using DI containers with things that are considered data in your system, Data in your case though it's hard to say what it is from the snippet.

@bigMOTOR
Copy link

@ilyapuchka Hi! Thanks for your response.
But tag is required to use it across all the chain of register and resolve actions and this is not so convenient as simple type inference ))
Is the idea of drop & create container per each view controller will not work any better?

@ilyapuchka
Copy link
Collaborator

ilyapuchka commented Jul 23, 2019

If you are using auto-injection or auto-wiring the container will pass the tag along when resolving all the dependencies and if they are registered separately with such tag then this definition will be used, otherwise it will fallback to definition without any tag.
Other than that you can try to register your different components in different containers and use proper container to resolve them. Common dependencies can go into a common container that you would use to resolve these dependencies manually or it can be linked to others as collaborating container so that it is used to resolve them automatically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants