Last active
July 11, 2019 19:08
-
-
Save nonameplum/676e475ce7dbb83fee0bce783557036e to your computer and use it in GitHub Desktop.
Very simple dependency container for swift
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 Foundation | |
public class Container { | |
//MARK:- Types | |
public enum ObjectLifeTime { | |
case persistent | |
case transient | |
} | |
private class Resolver { | |
let factory: (Container) -> Any | |
let objectLifeTime: ObjectLifeTime | |
var persistentObject: Any? = nil | |
init(factory: @escaping (Container) -> Any, objectLifeTime: ObjectLifeTime) { | |
self.factory = factory | |
self.objectLifeTime = objectLifeTime | |
} | |
func resolve(in container: Container) -> Any { | |
if objectLifeTime == .persistent { | |
if persistentObject != nil { | |
return persistentObject! | |
} | |
persistentObject = factory(container) | |
return persistentObject! | |
} | |
return factory(container) | |
} | |
} | |
//MARK:- Properties | |
private var dependencies: [String: Resolver] = [:] | |
//MARK:- Convenience | |
private func keyForType<T>(_ type: T.Type, name: String?) -> String { | |
return name ?? String(describing: type) | |
} | |
//MARK:- Public methods | |
public func register<T>(type: T.Type, name: String? = nil, objectLifeTime: ObjectLifeTime = .persistent, _ factory: @escaping (Container) -> Any) { | |
dependencies[keyForType(type, name: name)] = Resolver(factory: factory, objectLifeTime: objectLifeTime) | |
} | |
public func resolve<T>(type: T.Type, name: String? = nil) -> T { | |
guard let resolver = dependencies[keyForType(type, name: name)] else { | |
fatalError("Couldn't find definition for type: \(String(describing: type))" + (name != nil ? " registered with custom name: \(name!)" : "")) | |
} | |
let dependency = resolver.resolve(in: self) as! T | |
return dependency | |
} | |
deinit { | |
print("💥 Deinited \(String(describing: type(of: self)))") | |
} | |
} | |
/////////////////////////////////////////////////// | |
protocol ServiceProtocol {} | |
protocol InteractorProtocol: class { | |
var service: ServiceProtocol { get } | |
} | |
class Service: ServiceProtocol {} | |
class Interactor: InteractorProtocol { | |
let service: ServiceProtocol | |
init(service: ServiceProtocol) { | |
self.service = service | |
} | |
} | |
/////////////////////////////////////////////////// | |
// Check persistent case | |
var _container: Container? = Container() | |
_container?.register(type: ServiceProtocol.self, { (container) in | |
return Service() | |
}) | |
_container!.register(type: InteractorProtocol.self) { (container) in | |
let service = container.resolve(type: ServiceProtocol.self) | |
return Interactor(service: service) | |
} | |
let interactor1 = _container!.resolve(type: InteractorProtocol.self) | |
print(interactor1) // Dependency resolved! | |
let interactor2 = _container!.resolve(type: InteractorProtocol.self) | |
print(interactor2) | |
print("should be equal: \(interactor1 === interactor2)") | |
_container = nil // Deinit should be called! | |
/////////////////////////////////////////////////// | |
// Check transient case | |
var _container2: Container? = Container() | |
_container2?.register(type: ServiceProtocol.self, { (container) in | |
return Service() | |
}) | |
_container2!.register(type: InteractorProtocol.self, objectLifeTime: .transient) { (container) in | |
let service = container.resolve(type: ServiceProtocol.self) | |
return Interactor(service: service) | |
} | |
let interactor11 = _container2!.resolve(type: InteractorProtocol.self) | |
print(interactor11) // Dependency resolved! | |
let interactor22 = _container2!.resolve(type: InteractorProtocol.self) | |
print(interactor22) | |
print("shouldn't be equal: \(interactor11 === interactor22)") | |
_container2 = nil // Deinit should be called! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment