LazyContainer
is a simple library for lazy initialization of classes and structs.
Builder
class for registering and lazily initializing a single class or struct.LazyContainer
class for managing multiple Builder classes as a dependency manager or service locator.
App setups are often implemented in AppDelegate
or SceneDelegate
at launch, which is appropriate for crucial configurations. However, some configurations may not be immediately necessary and can be constructed when they are actually used. Heavy setup can also slow down app launch and affect testing and previewing. All initializations in AppDelegate
are also called during unit-tests and SwiftUI Previews, causing unnecessary overhead.
To improve this issue, we can use lazy loading. By delaying the execution of expensive operations until they are required, we can save time and memory. LazyContainer
makes it easy to achieve this efficiently.
What can this library do? It consists of two main classes, Builder
and LazyContainer
.
The Builder
class allows you to register a single class or struct and initialize it lazily later.
Using the Builder
class is easy. You simply call the Builder
and pass a closure that declares the class.
let builder = Builder { YourClass() }
// or
let secondBuilder = Builder {
let yourClass = YourClass()
return yourClass
}
You can access the registered instance by reading the dependency
from the builder. The first time you read the dependency
, the class will be instantiated. Subsequent reads will return the cached instance.
// first time: instantiate YourClass()
let yourClass = builder.dependency
// subsequent times: return cached YourClass()
let anotherClass = builder.dependency
LazyContainer is a Swift class that manages multiple Builder
classes as a service locator or DI container. It has two main features: register
and resolve
. This allows you to register a Builder
or closure and later resolve it by inferring the type.
let lazyContainer = LazyContainer()
let builder = Builder {
YourClass()
}
// Register
lazyContainer.register(builder)
// Resolve
let yourClass: YourClass = lazyContainer.resolve()
If you want to resolve services safely, use resolveOptional()
instead of resolve()
. The resolveOptional()
returns an optional value, so you can check if a service is registered before trying to access it.
let yourClass: YourClass? = lazyContainer.resolveOptional()
if let yourClass = yourClass {
// Use yourClass
} else {
// No service is registered
}
This avoids the fatalError
that would occur if you tried to access an unregistered service using resolve()
.
You can also register services using a closure.
lazyContainer.register { _ in
YourClass()
}
The container itself is passed as a parameter to the closure, allowing you to access other dependencies easily. This makes it easy to manage dependencies and avoid "dependency hell."
lazyContainer.register { _ in
ServiceD()
}
lazyContainer.register { container in
ServiceC(serviceD: container.resolve())
}
lazyContainer.register { container in
ServiceB(serviceD: container.resolve())
}
lazyContainer.register { container in
ServiceA(serviceB: container.resolve(), serviceC: container.resolve())
}
let serviceA: ServiceA = container.resolve()
// Service D -> Service B -> Service C -> Service A is created
For example, when you resolve ServiceA
, it will try to resolve its dependencies ServiceB
and ServiceC
, which in turn try to resolve their shared dependency ServiceD
. Once ServiceD
is created, ServiceB
and ServiceC
can be constructed, and finally ServiceA
is initialized.
The great thing about this approach is that if ServiceC
tries to resolve ServiceD
Dagain, it will return the cached instance that was already created for ServiceB
.
See more details in the Example project.
LazyContainer is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'LazyContainer'
The library is compatible with iOS 10 and above. The Example project uses SwiftUI, and requires iOS 13 or higher to run.
cookie777, takayuki-contact@gmail.com
LazyContainer is available under the MIT license. See the LICENSE file for more info.