Protocol Composition for Dependency Injection - Causality Dilemma / Compile Issue - swift

I am trying to use Swift "Protocol Composition" for dependency injection for the first time. There are various blog posts from well respected engineers in the field advocating this approach but I am unable to get the code to compile once there are dependencies that depend upon other dependencies.
The problem is that until your main concrete AllDependencies instance is initialised it cannot be used to initialise the child dependencies, but conversely you cannot create the child dependencies without the concrete AllDependencies instance.
Chicken & egg. Rock and hard place.
I'll try and provide the simplest example I can...
protocol HasAppInfo {
var appInfo: AppInfoProtocol { get }
}
protocol AppInfoProtocol {
var apiKey: String { get }
}
struct AppInfo: AppInfoProtocol {
let apiKey: String
}
protocol HasNetworking {
var networking: NetworkingProtocol { get }
}
protocol NetworkingProtocol {
func makeRequest()
}
class Networking: NetworkingProtocol {
typealias Dependencies = HasAppInfo
let dependencies: Dependencies
init(dependencies: Dependencies) {
self.dependencies = dependencies
}
func makeRequest() {
let apiKey = self.dependencies.appInfo.apiKey
// perform request sending API Key
// ...
}
}
class AllDependencies: HasAppInfo, HasNetworking {
let appInfo: AppInfoProtocol
let networking: NetworkingProtocol
init() {
self.appInfo = AppInfo(apiKey: "whatever")
/// **********************************************************
/// *** ERROR: Constant 'self.networking' used before being initialized
/// **********************************************************
self.networking = Networking(dependencies: self)
}
}
It seems like it might be possible to resolve this with use of lazy var, {get set} or mutating dependencies but that seems extermely unsafe because any code in your system can mutate your dependencies at will.
Would appreciate understanding how others have resolved what seems like a pretty fundamental issue with this approach.
References
http://merowing.info/2017/04/using-protocol-compositon-for-dependency-injection/
https://swiftwithmajid.com/2019/03/06/dependency-injection-in-swift-with-protocols/

You could use a private(set) lazy var:
private(set) lazy var networking: NetworkingProtocol = {
return Networking(dependencies: self)
}()

PS: I posted the original question. I have already accepted the lazy var answer, this is the simplest way forward, however I wanted to post this alternative solution that uses a generic DependencyFactory in case it helps others.
protocol Dependencies:
HasAppInfo &
HasNetworking
{}
class DependencyFactory {
typealias Factory<T> = (Dependencies) -> T
private enum DependencyState<T> {
case registered(Factory<T>)
case initialised(T)
}
private var dependencyStates = [String: Any]()
func register<T>(_ type: T.Type, factory: #escaping Factory<T>) {
dependencyStates[key(for: type)] = DependencyState<T>.registered(factory)
}
func unregister<T>(_ type: T.Type) {
dependencyStates[key(for: type)] = nil
}
func resolve<T>(_ type: T.Type, dependencies: Dependencies) -> T {
let key = self.key(for: type)
guard let dependencyState = dependencyStates[key] as? DependencyState<T> else {
fatalError("Attempt to access unregistered `\(type)` dependency")
}
switch dependencyState {
case let .registered(factoryClosure):
let dependency = factoryClosure(dependencies)
dependencyStates[key] = DependencyState<T>.initialised(dependency)
return dependency
case let .initialised(dependency):
return dependency
}
}
private func key<T>(for type: T.Type) -> String {
return String(reflecting: type)
}
}
class AllDependencies: Dependencies {
private let dependencyFactory = DependencyFactory()
init() {
dependencyFactory.register(AppInfoProtocol.self, factory: { dependencies in
return AppInfo(apiKey: "whatever")
})
dependencyFactory.register(NetworkingProtocol.self, factory: { dependencies in
return Networking(dependencies: dependencies)
})
}
var appInfo: AppInfo {
return dependencyFactory.resolve(AppInfoProtocol.self, dependencies: self)
}
var networking: Networking {
return dependencyFactory.resolve(NetworkingProtocol.self, dependencies: self)
}
}

Related

What is a good design pattern approach for a somewhat dynamic dependency injection in Swift

Let's say there are three components and their respective dynamic dependencies:
struct Component1 {
let dependency1: Dependency1
func convertOwnDependenciesToDependency2() -> Dependency2
}
struct Component2 {
let dependency2: Dependency2
let dependency3: Dependency3
func convertOwnDependenciesToDependency4() -> Dependency4
}
struct Component3 {
let dependency2: Dependency2
let dependency4: Dependency4
func convertOwnDependenciesToDependency5() -> Dependency5
}
Each of those components can generate results which can then be used as dependencies of other components. I want to type-safely inject the generated dependencies into the components which rely on them.
I have several approaches which I already worked out but I feel like I am missing something obvious which would make this whole task way easier.
The naive approach:
let component1 = Component1(dependency1: Dependency1())
let dependency2 = component1.convertOwnDependenciesToDependency2()
let component2 = Component2(dependency2: dependency2, dependency3: Dependency3())
let dependency4 = component2.convertOwnDependenciesToDependency4()
let component3 = Component3(dependency2: dependency2, dependency4: dependency4)
let result = component3.convertOwnDependenciesToDependency5()
Now I know that you could just imperatively call each of the functions and simply use the constructor of each component to inject their dependencies. However this approach does not scale very well. In a real scenario there would be up to ten of those components and a lot of call sites where this approach would be used. Therefore it would be very cumbersome to update each of the call sites if for instance Component3 would require another dependency.
The "SwiftUI" approach:
protocol EnvironmentKey {
associatedtype Value
}
struct EnvironmentValues {
private var storage: [ObjectIdentifier: Any] = [:]
subscript<Key>(_ type: Key.Type) -> Key.Value where Key: EnvironmentKey {
get { return storage[ObjectIdentifier(type)] as! Key.Value }
set { storage[ObjectIdentifier(type)] = newValue as Any }
}
}
struct Component1 {
func convertOwnDependenciesToDependency2(values: EnvironmentValues) {
let dependency1 = values[Dependency1Key.self]
// do some stuff with dependency1
values[Dependency2Key.self] = newDependency
}
}
struct Component2 {
func convertOwnDependenciesToDependency4(values: EnvironmentValues) {
let dependency2 = values[Dependency2Key.self]
let dependency3 = values[Dependency3Key.self]
// do some stuff with dependency2 and dependency3
values[Dependency4Key.self] = newDependency
}
}
struct Component3 {
func convertOwnDependenciesToDependency5(values: EnvironmentValues) {
let dependency2 = values[Dependency2Key.self]
let dependency4 = values[Dependency4Key.self]
// do some stuff with dependency2 and dependency4
values[Dependency5Key.self] = newDependency
}
}
But what I dislike with this approach is that you first of all have no type-safety and have to either optionally unwrap the dependency and give back an optional dependency which feels odd since what should a component do if the dependency is nil? Or force unwrap the dependencies like I did. But then the next point would be that there is no guarantee whatsoever that Dependency3 is already in the environment at the call site of convertOwnDependenciesToDependency4. Therefore this approach somehow weakens the contract between the components and could make up for unnecessary bugs.
Now I know SwiftUI has a defaultValue in its EnvironmentKey protocol but in my scenario this does not make sense since for instance Dependency4 has no way to instantiate itself without data required from Dependency2 or Depedency3 and therefore no default value.
The event bus approach
enum Event {
case dependency1(Dependency1)
case dependency2(Dependency2)
case dependency3(Dependency3)
case dependency4(Dependency4)
case dependency5(Dependency5)
}
protocol EventHandler {
func handleEvent(event: Event)
}
struct EventBus {
func subscribe(handler: EventHandler)
func send(event: Event)
}
struct Component1: EventHandler {
let bus: EventBus
let dependency1: Dependency1?
init(bus: EventBus) {
self.bus = bus
self.bus.subscribe(handler: self)
}
func handleEvent(event: Event) {
switch event {
case let .dependency1(dependency1): self.dependency1 = dependency1
}
if hasAllReceivedAllDependencies { generateDependency2() }
}
func generateDependency2() {
bus.send(newDependency)
}
}
struct Component2: EventHandler {
let dependency2: Dependency2?
let dependency3: Dependency3?
init(bus: EventBus) {
self.bus = bus
self.bus.subscribe(handler: self)
}
func handleEvent(event: Event) {
switch event {
case let .dependency2(dependency2): self.dependency2 = dependency2
case let .dependency3(dependency3): self.dependency3 = dependency3
}
if hasAllReceivedAllDependencies { generateDependency4() }
}
func generateDependency4() {
bus.send(newDependency)
}
}
struct Component3: EventHandler {
let dependency2: Dependency2?
let dependency4: Dependency4?
init(bus: EventBus) {
self.bus = bus
self.bus.subscribe(handler: self)
}
func handleEvent(event: Event) {
switch event {
case let .dependency2(dependency2): self.dependency2 = dependency2
case let .dependency4(dependency4): self.dependency4 = dependency4
}
if hasAllReceivedAllDependencies { generateDependency5() }
}
func generateDependency5() {
bus.send(newDependency)
}
}
I think in terms of type-safety and "dynamism" this approach would be a good fit. However to check if all dependencies were received already to start up the internal processes feels like a hack somehow. It feels like I am misusing this pattern in some form. Furthermore I think this approach may be able to "deadlock" if some dependency event was not sent and is therefore hard to debug where it got stuck. And again I would have to force unwrap the optionals in generateDependencyX but since this function would only get called if all optionals have a real value it seems safe to me.
I also took a look at some other design patterns (like chain-of-responsibility) but I couldn't really figure out how to model this pattern to my use-case.
My dream would be to somehow model a given design pattern as a result builder in the end so it would look something like:
FinalComponent {
Component1()
Component2()
Component3()
}
And in my opinion result builders would be possible with the "SwiftUI" and the event bus approach but they have the already described drawbacks. Again maybe I am missing an obvious design pattern which is already tailored to this situation or I am just modeling the problem in a wrong way. Maybe someone has a suggestion.

Better understanding of Dependency Injection - Resolving New Instances?

I have been working a job that requires me to focus on Dependency Injection. For posterity, I am using this in Swift/SwiftUI, though I believe my lack of understanding is more inherent in the concept than the language.
I have created a Dependency Injection container, which can be used to register and resolve types and components. As such;
protocol MyContainerProtocol {
func register<Component>(type: Component.Type, component: Any)
func resolve<Component>(type: Component.Type) -> Component?
}
final class MyContainer: MyContainerProtocol {
static let shared = DependencyContainer()
private init() { }
var components: [String: Any] = [:]
func register<Component>(type: Component.Type, component: Any) {
components["\(type)"] = component
}
func resolve<Component>(type: Component.Type) -> Component? {
return components["\(type)"] as? Component
}
}
This will become relevant below, but I have a class in my project, named VideoProcessor;
class VideoProcessor: SomeProtocol {
var codec: String
var format: String
init(codec: String, format: String) {
self.codec = codec
self.format = format
}
}
Early on in the app's lifecycle, I am registering the component. For example;
let container = DependencyContainer.shared
container.register(type: VideoProcessor.self, component: VideoProcessor(codec: "H264", format: "MP4"))
...
let processor = container.resolve(type: VideoProcessor.self)!
My Confusion: What is being asked of me is to resolve an instance of a type, without having to construct it when registering. Effectively, I'm being asked to resolve a new instance of a registered type each time it is resolved. In my mind, this means my code would resemble something like;
let container = DependencyContainer.shared
container.register(type: VideoProcessor.self)
...
let processorA = container.resolve(type: VideoProcessor.self)!
processorA.codec = "H264"
processorA.format = "MP4"
let processorB = container.resolve(type: VideoProcessor.self)!
processorB.codec = "H265"
processorB.format = "MOV"
However, VideoProcessor has its own dependencies, leading me to be unsure how I would register a type.
I'm unsure if my issue exists in the way my Dependency Container is built, the way my classes are built, or if the question of what's being asked of me I'm just not understanding. Even looking at popular Swift libraries like Swinject or DIP, I don't entirely see what my Container is doing improperly (or if this is where the Factory method comes in).
You would need to add an extra register function.
protocol MyContainerProtocol {
func register<Component>(type: Component.Type, component: Any)
func register<Component>(type: Component.Type, builder: #escaping (MyContainerProtocol) -> Component)
func resolve<Component>(type: Component.Type) -> Component?
}
final class MyContainer: MyContainerProtocol {
static let shared = MyContainer()
private init() { }
var components: [String: Any] = [:]
func register<Component>(type: Component.Type, component: Any) {
components["\(type)"] = component
}
func register<Component>(type: Component.Type, builder: #escaping (MyContainerProtocol) -> Component) {
components["\(type)"] = builder
}
func resolve<Component>(type: Component.Type) -> Component? {
if let singleton = components["\(type)"] as? Component {
return singleton
}
if let builder = components["\(type)"] as? (MyContainerProtocol) -> Component {
return builder(self)
}
return nil
}
}
Then it would look like this at the call site:
struct Animal {
let type: String
let id = UUID()
}
struct Person {
let name: String
let pet: Animal
let id = UUID()
}
class ComplicatedNetworkStack {
let id = UUID()
/// so much stuff in here
}
MyContainer.shared.register(type: Animal.self) { _ in Animal(type: "Dog") }
MyContainer.shared.register(type: Person.self) { container in
Person(
name: "Joe Dirt",
pet: container.resolve(type: Animal.self)!
)
}
MyContainer.shared.register(type: ComplicatedNetworkStack.self, component: ComplicatedNetworkStack())
If you were to run that code in a playground and resolve Person and Animal a few times, you'll see the UUID's are all different, while ComplicatedNetworkStack's id is the same.

How to correct implement provider logic using generics in Swift

I try to implement logic where some different objects can receive their unique configs.
I have a lot of objects with different types, which can request their own configuration object.
//Provider
protocol ConfigProvider {
func config<R: ConfigReciever>(for reciever: R) -> R.ConfigType
}
class Factory {
}
extension Factory: ConfigProvider {
func config<R: ConfigReciever>(for reciever: R) -> R.ConfigType {
//How switch?
return Config1(info: "hey") as! R.ConfigType
}
}
//Reciever
protocol ConfigReciever: class {
associatedtype ConfigType
var dataSource: ConfigProvider? { get set }
}
struct Config1 {
let info: String
}
class Object1: ConfigReciever {
typealias ConfigType = Config1
var dataSource: ConfigProvider?
func execute() {
let config = dataSource?.config(for: self)
print("\(config!.info)")
}
}
But have some problems with correct implement Provider logic.
I don't know how switch reciever to create correct Config type.
Is this any options?
I know, that i can make this without generics (for example with enum of configTypes), but i don't want to make unnecessary casts.
I would suggest using an intermediate protocol
// Wrapper container
protocol Container { }
extension String: Container { }
extension Int: Container { }
// Implementation
//Provider
protocol ConfigProvider {
func config<R>(for reciever: R) -> Configuration where R : ConfigReciever, R.ConfigType: Configuration
}
class Factory { }
extension Factory: ConfigProvider {
func config<R>(for reciever: R) -> Configuration where R : ConfigReciever, R.ConfigType: Configuration {
return Config1(info: "hey")
}
}
//Reciever
protocol ConfigReciever: class {
associatedtype ConfigType
var dataSource: ConfigProvider? { get set }
}
protocol Configuration {
var info: Container { get set }
}
struct Config1: Configuration {
var info: String
}
class Object1: ConfigReciever {
typealias ConfigType = Config1
var dataSource: ConfigProvider?
func execute() {
let config = dataSource?.config(for: self)
// here you should case into wanted structure:
if let stringInfo = config?.info as? String {
print("\(stringInfo)")
}
}
}
let factory = Factory()
let obj = Object1()
obj.dataSource = factory
obj.execute()

What does this Swift type error mean? It reads like what's expected is already the case

I'm stuck on a compilation error that I'm having trouble interpreting. The expected argument type appears identical to what I've passed to it, so I'm not sure what to make of it. Probably best to just paste the error and relevant bits of code.
Here's where it fails:
static func DefaultProvider() -> ReactiveManabiAPIProvider<ManabiAPI> {
return ReactiveManabiAPIProvider(endpointClosure: endpointsClosure,
requestClosure: endpointResolver(),
stubClosure: StubBehaviour,
plugins: APIProvider.plugins)
}
And the error message:
error: cannot convert value of type '(ManabiAPI) -> Endpoint' to expected argument type '_ -> Endpoint<_>'
return ReactiveManabiAPIProvider(endpointClosure: endpointsClosure,
^~~~~~~~~~~~~~~~
And some of the other relevant code referenced above:
enum ManabiAPI {
[...]
}
extension ManabiAPI : TargetType {
var baseURL: NSURL { return NSURL(string: "[...]")! }
var path: String {
[...]
}
var parameters: [String: AnyObject]? {
[...]
}
var method: ReactiveMoya.Method {
[...]
}
[...]
}
public class ReactiveManabiAPIProvider<Target where Target: TargetType> : ReactiveCocoaMoyaProvider<Target> {
var appController: AppController
var requestErrors: RACSubject
override init(endpointClosure: MoyaProvider<Target>.EndpointClosure = MoyaProvider.DefaultEndpointMapping,
requestClosure: MoyaProvider<Target>.RequestClosure = MoyaProvider.DefaultRequestMapping,
stubClosure: MoyaProvider<Target>.StubClosure = MoyaProvider.NeverStub,
manager: Manager = Alamofire.Manager.sharedInstance,
plugins: [PluginType] = [], stubScheduler: DateSchedulerType? = nil) {
let appDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
appController = appDelegate.appController!
requestErrors = RACSubject()
super.init(endpointClosure: endpointClosure, requestClosure: requestClosure, stubClosure: stubClosure, manager: manager, plugins: plugins)
}
[...]
}
Please let me know if it'd be useful to see anything else.
I have a difficult time trying this solution in a playground as your example above is still a bit too non-minimal. But I suspect you need to explicitly state the generic Target type (under type constraint TargetType) in the ReactiveManabiAPIProvider initializer in the return clause of your function DefaultProvider(). E.g.:
static func DefaultProvider() -> ReactiveManabiAPIProvider<ManabiAPI> {
return ReactiveManabiAPIProvider<ManabiAPI>(endpointClosure: endpointsClosure,
requestClosure: endpointResolver(),
stubClosure: StubBehaviour,
plugins: APIProvider.plugins)
}
Otherwise your return initializes a ReactiveManabiAPIProvider without an associated generic, and naturally the following return cast fails as function return expects a ReactiveManabiAPIProvider instance with generic Target type ManabiAPI.
That's the code where I have exactly the same problem (i'm using Moya 6.5.0)
public protocol ApiService {
var apiProvider: ReactiveCocoaMoyaProvider<ApiRouter> { get }
func request(token: ApiRouter) -> SignalProducer<Response, NSError>
}
public class ApiServiceImpl: ApiService {
private let application: UIApplication
public var apiProvider: ReactiveCocoaMoyaProvider<ApiRouter>
public init(stubbing: Bool, application: UIApplication) {
self.application = application
if stubbing == false {
let endpointsClosure = { (target: ApiRouter) -> Endpoint<ApiRouter> in
return Endpoint<ApiRouter>(
URL: ApiServiceImpl.url(target),
sampleResponseClosure: { .NetworkResponse(200, target.sampleData) },
method: target.method,
parameters: target.parameters
)
}
let networkActivityPlugin = NetworkActivityPlugin { type in
switch type {
case .Began : application.networkActivityIndicatorVisible = true
case .Ended : application.networkActivityIndicatorVisible = false
}
}
let networkLoggerPlugin = NetworkLoggerPlugin(verbose: true, responseDataFormatter: JSONResponseDataFormatter)
let plugins = [networkActivityPlugin, networkLoggerPlugin]
apiProvider = ReactiveCocoaMoyaProvider<ApiRouter>(endpointClosure: endpointsClosure, plugins: plugins)
} else {
apiProvider = ReactiveCocoaMoyaProvider<ApiRouter>(stubClosure: { _ in .Immediate })
}
}
public func request(token: ApiRouter) -> SignalProducer<Response, NSError> {
return apiProvider
.request(token)
.filterSuccessfulStatusAndRedirectCodes()
}
private static func url(route: TargetType) -> String {
return route.baseURL.URLByAppendingPathComponent(route.path).absoluteString
}
}
And i fixed that error by just adding [PluginType] to plugins array definition line, so it becomes
let plugins: [PluginType] = [networkActivityPlugin, networkLoggerPlugin]

Is there a better way to do dependency injection in Swift than this ?

New to swift, I was trying to create a service registry:
class ServiceRegistry {
static var instance = ServiceRegistry()
private var registry = [String:AnyObject]()
private init(){}
func register<T>(key:T, value:AnyObject) {
self.registry["\(T.self)"] = value
}
func get<T>(_:T) -> AnyObject? {
return registry["\(T.self)"]
}
}
but is not super friendly:
Register:
ServiceRegistry.instance.register(CacheServiceProtocol.self, value:ImageCacheService())
Retrieve:
if let cache = ServiceRegistry.instance.get(CacheServiceProtocol) as? CacheServiceProtocol { ... }
Any better way ? It would be useful to get rid of the as? CacheServiceProtocol in the if let ...
Swinject is a dependency injection framework for Swift. In your case, you can use it without the cast with as?.
Register:
let container = Container()
container.register(CacheServiceProtocol.self) { _ in ImageCacheService() }
Retrieve:
let cache = container.resolve(CacheServiceProtocol.self)!
Here cache is inferred as CacheServiceProtocol type. The resolve method returns nil if the specified type is not registered. We know CacheServiceProtocol is already registered, so the force-unwrap with ! is used.
UPDATE
I didn't exactly answer to the question. An implementation to remove the cast is storing factory closures instead of values in the registry. Here is the example. I also modified the type of key.
class ServiceRegistry {
static var instance = ServiceRegistry()
private var registry = [String:Any]()
private init(){}
func register<T>(key:T.Type, factory: () -> T) {
self.registry["\(T.self)"] = factory
}
func get<T>(_:T.Type) -> T? {
let factory = registry["\(T.self)"] as? () -> T
return factory.map { $0() }
}
}
Register:
ServiceRegistry.instance.register(CacheServiceProtocol.self) {
return ImageCacheService()
}
Retrieve:
// The type of cache is CacheServiceProtocol? without a cast.
let cache = ServiceRegistry.instance.get(CacheServiceProtocol.self)
Using #autoclosure might be also good.
I see your attempt to implement Service Locator design pattern. It's not Dependency Injection itself, but these two patterns actually can supplement each other.
I did implement a Service Locator in Swift 2 as well and I'm pretty happy with the result. Take a look at my code here: ServiceLocator.swift (ready to use) or BasicServiceLocator.swift and LazyServiceLocator.swift (with usage examples).
Here is the basic concept:
protocol ServiceLocator {
func getService<T>(type: T.Type) -> T?
func getService<T>() -> T?
}
extension ServiceLocator {
func getService<T>() -> T? {
return getService(T)
}
}
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
final class BasicServiceLocator: ServiceLocator {
// Service registry
private lazy var reg: Dictionary<String, Any> = [:]
func addService<T>(instance: T) {
let key = typeName(T)
reg[key] = instance
//print("Service added: \(key) / \(typeName(service))")
}
func getService<T>(type: T.Type) -> T? {
return reg[typeName(T)] as? T
}
}
And demonstration:
// Services declaration
protocol S1 {
func f1() -> String
}
protocol S2 {
func f2() -> String
}
// Services imlementation
class S1Impl: S1 {
func f1() -> String {
return "S1 OK"
}
}
class S2Impl: S2 {
func f2() -> String {
return "S2 OK"
}
}
// Service Locator initialization
let sl: ServiceLocator = {
let sl = BasicServiceLocator()
sl.addService(S1Impl() as S1)
sl.addService(S2Impl() as S2)
return sl
}()
// Test run
let s1 = sl.getService(S1)
let s2: S2? = sl.getService(S2)
print(s1?.f1() ?? "S1 NOT FOUND") // S1 OK
print(s2?.f2() ?? "S2 NOT FOUND") // S2 OK
As one of the other posters pointed out, the Service Locator pattern is not actually DI. Some would even go so far as to say it's an anti-pattern.
As a general answer to your question - I do believe first class DI is a better way to accomplish the above. My suggestion would be to use Typhoon but there are several other DI libs available for Swift such as Cleanse which looks very promising.