Skip to content

External

Andrey Pleshkov edited this page Apr 1, 2019 · 11 revisions

Sometimes it's necessary to configure a container with some external dependencies:

  • environment, launch arguments, ...
  • third-party object instances
  • your object instances
  • some constants
  • ...

Use the @saber.externals(One, Two, ...) annotation to add container externals. You can add more than one external.

// @saber.container(AppContainer)
// @saber.scope(App)
// @saber.externals(CoolEventTracker, AwesomeLogger)
protocol AppContaining {}

Then to create this container you have to provide all external instances manually to its initializer.

let appContainer = AppContainer(
    coolEventTracker: CoolSDK.sharedEventTracker,
    awesomeLogger: AwesomeLogger()
)

Constants as Dependencies

It's possible to provide needed constants as dependencies via externals.

Imagine there're two string constants: analyticsKey and filePath. So if we try to register them as is, Saber will fail to distinguish them:

// @saber.container(AppContainer)
// @saber.scope(App)
// @saber.externals(String, String)
protocol AppContaining {}

Let's use typealiases:

typealias AnalyticsKey = String

typealias FilePath = String

// @saber.container(AppContainer)
// @saber.scope(App)
// @saber.externals(AnalyticsKey, FilePath)
protocol AppContaining {}

Now we can create this container like:

let appContainer = AppContainer(
    analyticsKey: "abc123",
    filePath: "/path/to/file"
)

And use our externals somewhere:

// @saber.scope(App)
class MyService {
    
    // @saber.inject
    init(analyticsKey: AnalyticsKey, filePath: FilePath) {
        // ...
    }
}

Weak & Unowned Externals

NOTE: This feature is available from 0.2.1

By default externals are strong inside a container, but there are cases you don't want to retain them. Saber provides such functionality by attributing externals inside the annotation as weak or unowned. Also any external could be optional or force unwrapped and it doesn't matter what attribute you use.

  • Every weak external is stored as var due to the nature of weak references. Keep in mind Saber doesn't mark a weak external as optional automatically, so you have to add ? at the end by yourself (see example below).
  • Every unowned is stored as let - the same way a container stores every non-attributed (or strong) external.
// @saber.container(AppContainer)
// @saber.scope(App)
// @saber.externals(weak Foo, weak Bar?, unowned Baz, unowned Qux!)
protocol AppContaining {}

Thus it'll be generated as:

// NOTE: `internal` is used by default and can be changed via Saber configuration
class AppContiner: AppContaining {
    internal weak var foo: Foo // WON'T compile - should be optional (see `bar`)
    internal weak var bar: Bar?
    internal unowned let baz: Baz
    internal unowned let qux: Qux!

    internal init(foo: Foo, bar: Bar?, baz: Baz, qux: Qux!) {
        self.foo = foo
        self.bar = bar
        self.baz = baz
        self.qux = qux
    }
}
Clone this wiki locally