I'm using awesome Swinject for DI in my project, but I'm using it without assemblies (by the time I've started using Swinject, there was no assemblies).
My current pattern of using Containers
is:
class ParentContainer {
private let container: Container
init(parentContainer: Container?) {
container = Container(parent: parentContainer)
container.register....
}
func myTopLevelController() -> MyTopController {
let controller = container.resolve....
controller.container = self // controller holds its container
return controller
}
func childContainer() -> ChildContainer {
return ChildContainer(parentContainer: container)
}
}
class ChildContainer {
private let container: Container
init(parentContainer: Container?) {
....
}
With that configuration:
Container
even with manual building (my code doesn't know about any framework), as my code calls: let topController = ParentContainer().myTopLevelController()
Now I'm trying to apply Assembly
. As far as I can understand, my containers now will conform to AssemblyType
protocol. But I have some confusion:
func loaded(resolver: ResolverType)
method? should I retain resolver? Can it lead to retain cycle?1. Should I resolve instances through assembly, not through container?
It's up to you whether you use the assembly feature. It is used to manage grouping of dependencies. Since it looks you already manage the groups of dependencies by ParentContainer
and ChildContainer
, I think you don't have to use assemblies.
People who have used Typhoon might prefer the feature. People who have used another register
/resolve
type DI container might prefer organizing container structures by themself.
2. What is the purpose of func loaded(resolver: ResolverType) method? should I retain resolver? Can it lead to retain cycle?
It is called after all assemblies are applied to a container in order to do something that cannot run during assemble
method of an Assembly
. It is called by the system of Swinject like viewDidLoad
of UIViewController
called by the UIKit system. The documentation about loaded
or a unit test might help you understanding loaded
function.
You shouldn't store the resolver
parameter. (Actually I don't see usecases to store it because Assembler
doesn't keep references to assemblies, which will be released after you instantiate Assembler
. Even if you store it, no retain cycle is caused.)
3. I'd like to have TopLevelAssembly, but still use Containers for leaf entitites. Is it possible to pass Assembly as a parent for a container? Or are there any other way to achieve it?
I didn't catch your context about the TopLevelAssembly and leaf entities. I will be able to update my answer later if you add more details.
Here are some comments to the question parts: You cannot pass an Assembly
instance because the initializer of Container
is init(parent: Container? = nil)
, which takes an instance of Container
. Another way to achieve it might be just keeping the top level as Container
. (Or I have to update Swinject to support the scenario.)
My answer might not be perfect but I hope it helps you implement the service locator pattern.