I built a state management in my ios applications similar to redux in javascript. It work and it's nice to work with, but i want to abstract and decouple some part in a framework for reusability, testing and sharing.
To add some context, the main idea is to create a class store
with a getState
and dispatch
methods. A struct State
defined by the user is passed at the store initialization.
/* Store signature: class MyStore<State>: MyStoreProcotol */
let store = MyStore(state: ApplicationState())`
Once the store is initialized, i'm trying to inject it in any class (UIViewController for example, but not mandatory) that conform to ConnectionProtocol
.
In the code below, I pass the controller and the store to a function injectStoreInView
. I'm trying to inject the store in the controller from this function, func injectStoreInView<State>(viewController: UIViewController, store: MyStore<State>)
I've try several approaches with generics, whithout success. I have read on "type erasure" and follow tutorials, but i'm not sure if it help for this case and how to apply it. I have troubles to handle the type of the parameter store
of injectStoreInView, and can't assign it later in the controller controller.connection.store
.
This is the code, where a lot of parts has been removed to illustrate the problem. (This code does not work.)
Framework part:
import UIKit
/* store */
protocol MyStoreProcotol {
associatedtype State
func getState() -> State
}
class MyStore<State>: MyStoreProcotol {
var state: State
init(state: State) {
self.state = state
}
func getState() -> State {
return self.state
}
}
/* connection */
protocol ConnectionProtocol {
associatedtype State
var connection: Connection<State> { get }
}
class Connection<State> {
var store: MyStore<State>? = nil
}
func injectStoreInView<State>(
viewController: UIViewController,
store: MyStore<State>
) {
if let controller = viewController /* as ConnectionProtocol */ {
controller.connection.store = store
print("yeah !")
}
}
In the application part:
struct ApplicationState {
var counter = 0
}
class StartViewConnector: UIViewController, ConnectionProtocol {
let connection = Connection<ApplicationState>()
}
func appDelegatedidFinishLaunchingWithOptions() -> Bool {
let store = MyStore(state: ApplicationState())
let controller = StartViewConnector() // connector can be any class who conform to ConnectionProtocol, StartViewConnector for test but self.window?.rootViewController in iOS App
injectStoreInView(viewController: controller, store: store)
return true
}
appDelegatedidFinishLaunchingWithOptions()