Created
February 28, 2020 17:45
-
-
Save joemasilotti/c36fc184b3c65eed4bb511c4afc32e17 to your computer and use it in GitHub Desktop.
Roll your own iOS dependency injection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
/* ... */ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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?