Skip to content

Instantly share code, notes, and snippets.

@gazdagsandor
Last active September 24, 2018 14:30
Show Gist options
  • Save gazdagsandor/d6ca15c2da62bbcfae599afb2612803f to your computer and use it in GitHub Desktop.
Save gazdagsandor/d6ca15c2da62bbcfae599afb2612803f to your computer and use it in GitHub Desktop.
DI container supereasy
import UIKit
// Non thread safe DI container simple implementation
class Container {
var services: [String: Factory] = [:]
func register<Service: AnyObject>(service: Service.Type, factory: @escaping () -> Service) {
let creator = FactoryImpl<Service>(with: factory, isSingleton: false)
let key = String(describing: service.self)
services[key] = creator
}
func registerSingleton<Service: AnyObject>(service: Service.Type, factory: @escaping () -> Service) {
let creator = FactoryImpl<Service>(with: factory, isSingleton: true)
let key = String(describing: service.self)
services[key] = creator
}
func inject<Service: AnyObject>() -> Service {
let key = String(describing: Service.self)
guard let service = services[key] else {
fatalError("Need to register your thingies first mate.")
}
return service.execute() as! Service
}
}
// Instance Creation
protocol Factory {
func execute() -> AnyObject
}
class FactoryImpl<Service: AnyObject>: Factory {
var factory: () -> Service
var object: Service!
var isSingleton: Bool = false
init(with factory: @escaping () -> Service, isSingleton: Bool) {
self.factory = factory
self.isSingleton = isSingleton
}
func execute() -> AnyObject {
if isSingleton {
if object == nil {
object = factory()
}
return object
}
else {
return factory()
}
}
}
// Actual Usage //
protocol Animal {
func sing() -> String
}
class Cat : Animal {
func sing() -> String {
return "Meow"
}
}
class Dog : Animal {
func sing() -> String {
return "Wooof"
}
}
class DogDiety: Dog {
override func sing() -> String {
return "HARRR I guard the gates of the underworld mortal!!! Lalalalala..."
}
}
protocol Something {
func justDoIt()
}
class SomethingImpl: Something {
func justDoIt() {
print("Yeah I'm doing it. Don't you see?")
}
}
let container = Container()
container.register(service: Cat.self) { () -> Cat in
return Cat()
}
container.register(service: Dog.self) { () -> Dog in
return Dog()
}
container.registerSingleton(service: DogDiety.self) { () -> DogDiety in
return DogDiety()
}
// Creating instances
let puss: Cat = container.inject() // Here is the reason why I love Swift
let fluffy = container.inject() as Dog // and it's type inference
// when I forget about that terrible compile time
let cerberus: DogDiety = container.inject()
let garmr: DogDiety = container.inject()
// Verifying instance behaviour
print(puss.sing())
print(fluffy.sing())
print(cerberus.sing())
print(garmr.sing())
// Verifying instance addresses
print(Unmanaged.passUnretained(puss).toOpaque())
print(Unmanaged.passUnretained(fluffy).toOpaque())
print(Unmanaged.passUnretained(cerberus).toOpaque())
print(Unmanaged.passUnretained(garmr).toOpaque())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment