Skip to content

Instantly share code, notes, and snippets.

@maximkrouk
Last active May 26, 2021 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maximkrouk/8ab244d618158199ffe2160d29818915 to your computer and use it in GitHub Desktop.
Save maximkrouk/8ab244d618158199ffe2160d29818915 to your computer and use it in GitHub Desktop.
import Combine
import ComposableArchitecture
import DeclarativeConfiguration
import SwiftUI
public protocol ComposableCoreProtocol {
associatedtype State
associatedtype Action
var store: ComposableArchitecture.Store<State, Action>? { get }
var viewStore: ComposableArchitecture.ViewStore<State, Action>? { get }
}
extension ComposableCoreProtocol {
public typealias Store = ComposableArchitecture.Store<State, Action>
public typealias ViewStore = ComposableArchitecture.ViewStore<State, Action>
public typealias Subscriptions = Set<AnyCancellable>
}
/// Protocol that enables you to use composable core and provides convenient typealiases for it
public protocol ComposableCoreProvider {
associatedtype State: Equatable
associatedtype Action
var core: ComposableCore<State, Action> { get }
}
extension ComposableCoreProvider {
public typealias Core = ComposableCore<State, Action>
public typealias Store = Core.Store
public typealias ViewStore = Core.ViewStore
}
public class ComposableCore<State: Equatable, Action>: ComposableCoreProtocol {
public typealias Store = ComposableArchitecture.Store<State, Action>
public typealias ViewStore = ComposableArchitecture.ViewStore<State, Action>
public typealias StorePublisher = ComposableArchitecture.StorePublisher<State>
public typealias Subscriptions = Set<AnyCancellable>
public var state: State? { viewStore?.state }
private(set) public var store: Store?
private(set) public var viewStore: ViewStore?
private var localSubscriptions: Subscriptions = []
private var stateSubscriptions: Subscriptions = []
private let lock = NSLock()
private var _bind: ((StorePublisher, inout Subscriptions) -> Void)?
/// Handler for state rebinding on the `setStore` method call
public func bind(perfrom action: ((StorePublisher, inout Subscriptions) -> Void)?) {
self._bind = action
}
/// Handler for state rebinding on the `setStore` method call
@Handler<Store?>
public var scope
/// Handler for the `setStore` method
@Handler2<Store?, Store?>
public var storeWillSet
/// Handler for the `setStore` method completion
@Handler2<Store?, Store?>
public var storeWasSet
public init() {}
public func setStore(_ store: ComposableArchitecture.Store<State?, Action>) {
localSubscriptions.removeAll()
store.ifLet(
then: { [weak self] store in
self?.setStore(store)
},
else: { [weak self] in
self?.setStore(nil)
}
).store(in: &localSubscriptions)
}
public func setStore(_ store: Store?) {
localSubscriptions.removeAll()
let oldStore = self.store
self._storeWillSet(oldStore, store)
self.store = store
self.viewStore = store.map(ViewStore.init)
self._scope(store)
self.subscribeToStateChanges()
self._storeWasSet(oldStore, store)
}
public func subscribeToStateChanges() {
lock.lock()
stateSubscriptions.removeAll()
if let statePublishser = viewStore?.publisher {
_bind?(statePublishser, &stateSubscriptions)
}
lock.unlock()
}
public func send(_ action: Action) {
viewStore.map { $0.send(action) }
}
public func send(_ action: Action, animation: Animation?) {
viewStore.map { $0.send(action, animation: animation) }
}
}
import ComposableArchitecture
import Combine
public protocol ComposableObjectProtocol: NSObject, ComposableCoreProvider {
func commonInit()
func scope(_ store: Store?)
func storeWillSet(
from oldStore: Store?,
to newStore: Store?
)
func storeWasSet(
from oldStore: Store?,
to newStore: Store?
)
func bind(
_ state: StorePublisher<State>,
into subscriptions: inout Core.Subscriptions
)
}
extension ComposableObjectProtocol {
public func __setupCore() {
core.scope { [weak self] store in
self?.scope(store)
}
core.storeWillSet { [weak self] old, new in
self?.storeWillSet(from: old, to: new)
}
core.storeWasSet { [weak self] old, new in
self?.storeWasSet(from: old, to: new)
}
core.bind { [weak self] state, subscriptions in
self?.bind(state, into: &subscriptions)
}
}
}
open class NSComposableObject<State: Equatable, Action>: NSObject, ComposableObjectProtocol {
public let core: ComposableCore<State, Action> = .init()
public var subscriptions: Set<AnyCancellable> = []
public override init() {
super.init()
commonInit()
}
open func commonInit() {
__setupCore()
}
open func scope(_ store: Store<State, Action>?) {}
open func storeWillSet(
from oldStore: Store<State, Action>?,
to newStore: Store<State, Action>?
) {}
open func storeWasSet(
from oldStore: Store<State, Action>?,
to newStore: Store<State, Action>?
) {}
open func bind(
_ state: StorePublisher<State>,
into subscriptions: inout Core.Subscriptions
) {}
}
@maximkrouk
Copy link
Author

maximkrouk commented May 17, 2021

You also can create your own composable classes like ComposableViewController by copy-pasting NSComposableObject implementation details

Back to index

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment