Skip to content

Instantly share code, notes, and snippets.

@simme
Created December 10, 2020 14:40
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 simme/d6b57b3f738058ba812b5d34acd2767a to your computer and use it in GitHub Desktop.
Save simme/d6b57b3f738058ba812b5d34acd2767a to your computer and use it in GitHub Desktop.
Composable Architecutre helpers
import Combine
import ComposableArchitecture
import UIKit
/// The state store cell is a cell superclass designed to work with Composable Architecture state stores. It removes
/// much of the boiler plate involved with creating a custom cell subclass.
open class StateStoreCell<State: Equatable, Action>: UICollectionViewCell {
// MARK: Properties
/// Any current store for this cell.
public var store: Store<State, Action>?
/// Any current view store for this cell.
public var viewStore: ViewStore<State, Action>?
/// A place to store cancallables for state subscriptions.
public var cancellables: Set<AnyCancellable> = []
// MARK: Initialization
public override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
@available(*, unavailable) public required init?(coder: NSCoder) { fatalError() }
// MARK: Configuration
/// Configure the cell with the given store.
///
/// - Parameter store: The store to use for the cell.
public func configure(with store: Store<State, Action>) {
let viewStore = ViewStore(store)
self.store = store
self.viewStore = viewStore
configureStateObservation(on: viewStore)
}
// MARK: Cell Lifecycle
open override func prepareForReuse() {
super.prepareForReuse()
cancellables.removeAll()
store = nil
viewStore = nil
}
// MARK: Subclass API
/// Override this method to configure state observation whenever the cell is configured with a new store.
///
/// - Parameter viewStore: The view store that was created as part of the configuration.
open func configureStateObservation(on viewStore: ViewStore<State, Action>) { }
/// Override this method to setup views when a cell is created.
open func setupViews() { }
}
import Combine
import ComposableArchitecture
import UIKit
/// The state store reusable view is a superclass designed to work with Composable Architecture state stores. It removes
/// much of the boiler plate involved with creating a custom collection view reusable view subclass.
open class StateStoreCollectionReusableView<State: Equatable, Action>: UICollectionReusableView {
// MARK: Properties
/// Any current store for this reusable view.
public var store: Store<State, Action>?
/// Any current view store for this reusable view.
public var viewStore: ViewStore<State, Action>?
/// A place to store cancallables for state subscriptions.
public var cancellables: Set<AnyCancellable> = []
// MARK: Initialization
public override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
@available(*, unavailable) public required init?(coder: NSCoder) { fatalError() }
// MARK: Configuration
/// Configure the reusable view with the given store.
///
/// - Parameter store: The store to use for the reusable view.
public func configure(with store: Store<State, Action>) {
let viewStore = ViewStore(store)
self.store = store
self.viewStore = viewStore
configureStateObservation(on: viewStore)
}
// MARK: Reusable View Lifecycle
open override func prepareForReuse() {
super.prepareForReuse()
cancellables.removeAll()
store = nil
viewStore = nil
}
// MARK: Subclass API
/// Override this method to configure state observation whenever the view is configured with a new store.
///
/// - Parameter viewStore: The view store that was created as part of the configuration.
open func configureStateObservation(on viewStore: ViewStore<State, Action>) { }
/// Override this method to setup views when a view is created.
open func setupViews() { }
}
import Combine
import ComposableArchitecture
import UIKit
/// The state store cell is a UIControl superclass designed to work with Composable Architecture state stores.
/// It removes much of the boiler plate involved with creating a custom control subclass.
open class StateStoreControl<State: Equatable, Action>: UIControl {
// MARK: Properties
/// Any current store for this control.
public var store: Store<State, Action>
/// Any current view store for this control.
public var viewStore: ViewStore<State, Action>
/// A place to store cancallables for state subscriptions.
public var cancellables: Set<AnyCancellable> = []
// MARK: Initialization
/// Create a new state store control with the given store.
///
/// - Parameter store: The store that manages the state.
///
/// - Returns: A new state store control
public init(store: Store<State, Action>) {
self.store = store
self.viewStore = ViewStore(store)
super.init(frame: .zero)
configureControl()
configureStateObservation(on: viewStore)
}
@available(*, unavailable) public required init?(coder: NSCoder) { fatalError() }
// MARK: Subclass API
/// Override this method to configure state observation.
///
/// - Parameter viewStore: The view store to observe.
open func configureStateObservation(on viewStore: ViewStore<State, Action>) { }
/// Override this method to setup views when a cell is created.
open func configureControl() { }
}
import Combine
import ComposableArchitecture
import UIKit
/// Convenience class for views that are powered by state stores.
open class StateStoreView<State: Equatable, Action>: UIView {
// MARK: Properties
/// The store powering the view.
open var store: Store<State, Action>
/// The view store wrapping the store for the view.
open var viewStore: ViewStore<State, Action>
/// Keeps track of subscriptions.
open var cancellables: Set<AnyCancellable> = []
// MARK: Initialization
/// Creates a new store view with the given store.
///
/// - Parameter frame: The initial frame of the view.
/// - Parameter store: The store to use with the view.
///
/// - Returns: A new view controller.
public init(frame: CGRect = .zero, store: Store<State, Action>) {
self.store = store
self.viewStore = ViewStore(store)
super.init(frame: frame)
configureView()
configureStateObservation(on: viewStore)
}
@available(*, unavailable) public required init?(coder: NSCoder) {
fatalError("Not implemented")
}
// MARK: Subclass API
/// Override this method to configure state observation.
///
/// - Parameter viewStore: The view store to observe.
open func configureStateObservation(on viewStore: ViewStore<State, Action>) { }
/// Override this method to setup views when a cell is created.
open func configureView() { }
}
import Combine
import ComposableArchitecture
import UIKit
/// Convenience class for view controllers that are powered by state stores.
open class StateStoreViewController<State: Equatable, Action>: UIViewController {
// MARK: Properties
/// The store powering the view controller.
open var store: Store<State, Action>
/// The view store wrapping the store for the actual view.
open var viewStore: ViewStore<State, Action>
/// Keeps track of subscriptions.
open var cancellables: Set<AnyCancellable> = []
// MARK: Initialization
/// Creates a new store view controller with the given store.
///
/// - Parameter store: The store to use with the view controller.
///
/// - Returns: A new view controller.
public init(store: Store<State, Action>) {
self.store = store
self.viewStore = ViewStore(store)
super.init(nibName: nil, bundle: nil)
configureStateObservation(on: viewStore)
}
@available(*, unavailable) public required init?(coder: NSCoder) {
fatalError("Not implemented")
}
// MARK: Subclass API
/// Override this method to configure state observation.
///
/// - Parameter viewStore: The view store to observe.
open func configureStateObservation(on viewStore: ViewStore<State, Action>) { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment