As mentioned in the introduction, in order for Resolve to resolve a request for a paticular service you first need to register a factory that knows how to instantiate an instance of the service.
Resolver.register { NetworkService() }
Resolver will then automatically use that factory whenever it's asked to resolve an instance of NetworkService
.
class MyViewModel {
@Injected var network: NetworkService
}
Pretty straightforward, right? We need to register our services.
But where do we put those all of those registrations?
Well, it's a common practice with Resolver, Swinject, and other DI systems to add addtional "injection" files to your project to support the dependencies needed by a particular part of the code base.
Let's start by adding the master injection file for the entire application.
Add a file named AppDelegate+Injection.swift
to your project and add the following code:
import Resolver
extension Resolver: ResolverRegistering {
public static func registerAllServices() {
}
}
If you're using frameworks, CocoaPods or Carthage, you'll need the import Resolver
line. If you added Resolver.swift directly to your project, just delete that line.
Resolver automatically calls the registerAllServices
function the very first time it's asked to resolve a particular service. But as is, it's not very useful until you actually register some classes.
Note that we add our registration functionality directly into the Resolver namespace. This gives our registration factories direct access to the registration and resolution functions contained within that namespace. (e.g. register
, resolve
, etc..)
As mentioned above, we add addtional "injection" files to our projects to support the dependencies needed by a particular part of the code base.
Let's say you have a group in your project folder named "NetworkServices", and you want to register some of those services for use by Resolver.
Go to the NetworkServices folder and add a swift file named: NetworkServices+Injection.swift
, then add the following to that file...
#import Resolver
extension Resolver {
public static func registerMyNetworkServices() {
}
}
Now, go back to your AppDelegate+Injection.swift
file and add a reference to registerMyNetworkServices
.
extension Resolver: ResolverRegistering {
public static func registerAllServices() {
registerMyNetworkServices()
}
}
Resolver will automatically call registerAllServices
, and that function in turn calls each of your own registration functions.
Now, housekeeping completed, return to NetworkServices+Injection.swift
and add your own registrations.
Just as an example:
import Resolver
extension Resolver {
public static func registerMyNetworkServices() {
// Register protocols XYZFetching and XYZUpdating and create implementation object
register { XYZCombinedService() }
.implements(XYZFetching.self)
.implements(XYZUpdating.self)
// Register XYZNetworkService and return instance in factory closure
register { XYZNetworkService(session: resolve()) }
// Register XYZSessionService and return instance in factory closure
register { XYZSessionService() }
}
}
That's it. Resolver uses Swift type inference to automatically determine and register the type of object being returned by the registration factory.
And in the case of XYZNetworkService
, Resolver is used to infer the type of the session parameter that's needed to initialize a XYZNetworkService
.
This works with classes, structs, and protocols, though there are a few special cases and considerations for protocols.
You can also register value types, though that too has a few special considerations.