Kevin Renskers
Kevin Renskers

Reputation: 5980

Dependency Injection pointfree.co-style: dependencies with dependencies?

I'm really interested in the Dependency Injection pattern as designed / talked about by the pointfree.co guys, where you have an Environment struct that holds mutable properties of all dependencies.

In short, this pattern:

struct Environment {
  var analytics = Analytics()
  var date: () -> Date = Date.init
  var gitHub = GitHub()
}

var Current = Environment()

You can see their basic example here, and a bigger one here.

What I am trying to do though, is to be able to have dependencies that need dependencies. For example, an Analytics tracker that needs a Network provider to post some data.

import Foundation

// MARK: - NetworkProvider

struct NetworkProvider {
  var postData = { (data: Data) in
    print("Data posted using the `NetworkProvider`")
  }
}

extension NetworkProvider {
  static let mock = NetworkProvider(
    postData: { data in
      print("Mock post!")
    }
  )
}


// MARK: - Tracker

struct Tracker {
  var networkProvider = NetworkProvider()

  var track = { (event: String) in
    print("Tracked: \(event)")
    let data = event.data(using: .utf8)!
    networkProvider.postData(data) // <- ERROR
  }
}

extension Tracker {
  static let mock = Tracker(
    networkProvider: .mock,
    track: { event in
      print("Mocked tracked: \(event)")
    }
  )
}


// MARK: - Environment

struct Environment {
  var networkProvider = NetworkProvider()
  var tracker = Tracker()
}

extension Environment {
  static let mock = Environment(
    networkProvider: .mock,
    tracker: .mock
  )
}

The code above doesn't compile: Instance member 'networkProvider' cannot be used on type 'Tracker', which makes total sense. I can turn the networkProvider property into a static var but then I can no longer pass in a mock version, so that's not helpful.

How would I be able to use this method of Dependency Injection, while making it possible to have dependencies that need dependencies?

Upvotes: 1

Views: 596

Answers (1)

Joakim Danielson
Joakim Danielson

Reputation: 52118

You can’t access self in a computed property directly but it is possible if you declare it as a lazy variable

lazy var track = { [self] (event: String) in ...

Upvotes: 3

Related Questions