Last active
September 24, 2018 14:30
-
-
Save gazdagsandor/d6ca15c2da62bbcfae599afb2612803f to your computer and use it in GitHub Desktop.
DI container supereasy
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
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