Skip to content

Instantly share code, notes, and snippets.

@joemasilotti
Created February 28, 2020 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joemasilotti/c36fc184b3c65eed4bb511c4afc32e17 to your computer and use it in GitHub Desktop.
Save joemasilotti/c36fc184b3c65eed4bb511c4afc32e17 to your computer and use it in GitHub Desktop.
Roll your own iOS dependency injection
protocol Injectable: class {
var router: Routable { get }
}
class Injector: Injectable {
lazy var router: Routable { Router() }()
}
protocol Routable {
func route(url: String)
}
class Router: Routable {
func route(url: String) {
/* ... */
}
}
class Controller {
let router: Routable
init(injector: Injectable = Injector()) {
self.router = injector
}
func clicked(url: String) {
router.route(url: url)
}
}
class Application {
func start() {
let controller = Controller()
/* ... */
}
}
class FakeInjector: Injectable {
lazy var router: Routable { FakeRouter() }()
}
class FakeRoutable: Routable {
private(set) var lastRoutedUrl: String?
func route(url: String) {
lastRoutedUrl = url
}
}
class ControllerSpec: QuickSpec {
override func spec() {
var subject: Controller!
var injector: FakeInjectable!
var router: FakeRoutable!
beforeEach() {
injector = FakeInjectable()
injector.router = FakeRouteable!
subject = Controller(injector: injector)
}
describe("click a URL") {
it("routes the URL via the router") {
let url = "https://masilotti.com"
subject.click(url: url)
expect(router.lastRoutedUrl).to(equal(url))
}
}
}
}
@joemasilotti
Copy link
Author

I'm toying around with this approach to dependency injection on iOS.

The goal is that you never actually pass a (static) dependency around in your application code. injector is always a default argument so you get that for free. Then, when under test you inject your fake version with everything stubbed out.

The first obvious problem is that Injectable grows linearly with your application. But since the code ends up being fairly simple, perhaps that's not too terrible?

What do y'all think? Am I missing something obvious that will bite me?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment