Skip to content

Runtime arguments

Ilya Puchka edited this page Mar 9, 2018 · 6 revisions

Sometimes you need to register components that depend on some runtime arguments. For that you can register this component with a factory that accepts this parameter. When you resolve this component you will need to provide a value for this argument and it will be propagated to the factory:

container.register() { (url: String) in URLSessionNetworkLayer(baseURL: url) as NetworkLayer  }

let network = try! container.resolve(arguments: "http://prod.myapi.com/api/") as NetworkLayer
  • Dip supports up to 6 runtime arguments. If that is not enougth you can extend DependencyContainer to support more arguments. However, if you find yourself thinking about adding more runtime arguments, stop and think about your design instead. Having too many dependencies could be a sign of some problem in your architecture, so we strongly suggest that you refrain from doing so; six runtime arguments is already a lot.

  • Types, number and order of arguments matters and you can register different factories with different set of runtime arguments for the same protocol. To resolve using one of this factory you will need to pass runtime arguments of the same types, number and in the same order to resolve as you used in register method.

  • Always explicitly specify types of runtime arguments. It will make your registrations more clear and will help you to avoid mistakes when Swift type inference will infer argument's type as Optional. The following code will fail to resolve URLSessionNetworkLayer because Swift type system will infer factory argument type as String?, but String value is provided to resolve:

class URLSessionNetworkLayer {
    init(baseURL: String?) { ... }
}

container.register() { url in URLSessionNetworkLayer(baseURL: url) as NetworkLayer  }

//this will throw an error
let network = try! container.resolve(arguments: "http://prod.myapi.com/api/") as NetworkLayer

container.register() { (url: String) in URLSessionNetworkLayer(baseURL: url) as NetworkLayer  }

//this will successfully resolve
let network = try! container.resolve(arguments: "http://prod.myapi.com/api/") as NetworkLayer

Warning: container does not check values of runtime arguments when resolving components. So if you try to resolve new instance with another values of runtime arguments you may get back the same instance as before depending on the scope used to register its type (shared or only of singleton scopes)