Skip to content

Lazy Injections

apleshkov edited this page Aug 12, 2018 · 4 revisions

There're some cases when you want to get a dependency on demand. For example it's too "heavy" to create, so you don't want to slow your app launch.

Saber considers any injection as lazy if it's a lambda with a return value and no arguments:

() -> Dependency

Every type of injection supports laziness.

// @saber.scope(App)
// @saber.cached
class UserStorage {

    init() {
        // very heavy initialization
    }
}

// @saber.scope(App)
class UserManager {
    
    // @saber.inject
    // It's better to inject via initializer,
    // but we use a property injection here
    // for the sake of demonstration how to
    // use lazy + force unwrapping
    var userStorage: (() -> UserStorage)!
    
    func userName(id: String) -> String? {
        // NOTE: UserStorage is *cached* (see above), so
        //       we don't need to store its instance here
        return userStorage().user(id: id).name
    }
}

Note that containers inject lazy dependencies as { [unowned self] in return self.dependency }, so please be careful.

Typealias

It's possible to simplify your lazy injections with a typealias.

To "tell" Saber about such type alias, you provide its name via a configuration:

lazyTypealias: LazyInjection

Then define it in your code like:

typealias LazyInjection<T> = () -> T

Saber will consider T as a service to inject lazily:

// @saber.scope(App)
class Foo {

    // @saber.inject
    var baz: LazyInjection<Baz>!

    // @saber.inject
    init(bar: LazyInjection<Bar>) { ... }
}
Clone this wiki locally