Skip to content

Instantly share code, notes, and snippets.

@crsantos
Forked from FGoessler/ServiceLocator.swift
Last active May 26, 2020 14:52
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crsantos/fa14d420f8bf516b46a0bac491e1453b to your computer and use it in GitHub Desktop.
Save crsantos/fa14d420f8bf516b46a0bac491e1453b to your computer and use it in GitHub Desktop.
A very lightweight ServiceLocator implementation including a module mechanism written in Swift.
import Foundation
public typealias ServiceFactoryClosure<Service> = () -> Service
public protocol ServiceLocatorModule {
func registerServices(_ serviceLocator: ServiceLocator)
}
public class ServiceLocator {
fileprivate var registry = [ObjectIdentifier: Any]()
public static var sharedLocator = ServiceLocator()
init() {
self.registerModules( [CocoaDefaultModule()] )
}
// MARK: Registration
public func register<Service>(_ factory: @escaping ServiceFactoryClosure<Service>) {
let serviceId = ObjectIdentifier(Service.self)
self.registry[serviceId] = factory
}
public static func register<Service>(_ factory: @escaping ServiceFactoryClosure<Service>) {
self.sharedLocator.register(factory)
}
public func registerSingleton<Service>(_ singletonInstance: Service) {
let serviceId = ObjectIdentifier(Service.self)
self.registry[serviceId] = singletonInstance
}
public static func registerSingleton<Service>(_ singletonInstance: Service) {
self.sharedLocator.registerSingleton(singletonInstance)
}
public func registerModules(_ modules: [ServiceLocatorModule]) {
modules.forEach { $0.registerServices(self) }
}
public static func registerModules(modules: [ServiceLocatorModule]) {
self.sharedLocator.registerModules(modules)
}
public static func inject<Service>() -> Service {
return self.sharedLocator.inject()
}
}
// MARK: Private
fileprivate extension ServiceLocator {
/// This method is private because no service which wants to request other services should
/// bind itself to specific instance of a service locator.
///
/// - Returns: the injected service
func inject<Service>() -> Service {
let serviceId = ObjectIdentifier(Service.self)
if let factory = registry[serviceId] as? ServiceFactoryClosure<Service> {
return factory()
} else if let singletonInstance = registry[serviceId] as? Service {
return singletonInstance
} else {
fatalError("No registered entry for \(Service.self)")
}
}
}
class CocoaDefaultModule: ServiceLocatorModule {
func registerServices(_ serviceLocator: ServiceLocator) {
serviceLocator.register { NotificationCenter.default }
serviceLocator.register { UserDefaults.standard }
serviceLocator.register { URLSession.shared }
serviceLocator.register { UIScreen.main }
serviceLocator.register { UIApplication.shared }
serviceLocator.register { UIApplication.shared.delegate! }
}
}
// Examples
//
// Singleton
let myRealService = URLSession.shared
// VS
// DI'd
let myService: URLSession = ServiceLocator.inject()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment