CaptureContext/composable-architecture-extensions
Extension for TCA library (Update on hold, have to release major update to combine-navigation first)
Table of contents
- ComposableCore - ComposableCocoa - ComposableSwiftUI - ComposableExtensions
Products
ComposableCore
ComposableCore
Core manages underlying optional store, enables users to design UI components with lazy logical bindings. This approach allows to derive configuration logic out of initializers and treat components (primarilly UI-components) as containers that can exist without any logic.
Composable(NS)Object
Is a generic object driven by the core, since Swift doesn't allow inheritance from multiple classes, not every class that conforms to ComposableObjectProtocol can be downcasted to ComposableObject, good example is ComposableObject and ComposableNSObject classes, which are not interchangeable. Provides helpers for binding and scoping cores.
class ExampleObject: ComposableObjectOf<ExampleFeature> {
override func scope(_ store: Store?) {
super.scope(store)
childObject.core.setStore(store?.scope(
state: \.child.state,
action: \.child.action
))
}
override func bind(
_ store: Store,
into cancellables: Core.Cancellables
) {
super.bind(store, into: cancellables)
// This API is not yet available
store.observe(\.text)
.assign(to: self, \.text)
.store(in: cancellables)
}
}PullbackReducer
Pullbacks improve Reducers composition by replacing switch statements.
Pullback(\.path.to.child.action) { state in
return .send(.parentAction)
}
Pullback(\.path.to.child.action) { state, childAction in
return .send(.parentAction)
}
Pullback(\.path.to.children, action: \.child.action) { state, id, childAction in
return .send(.parentAction)
}OnChangeReducer
Allows to track changes in derived states.
SomeReducer().onChange(of: \.localState) { state, oldValue, newValue in
return .send(.parentAction)
}ForEachReducer
Indexed ForEach is useful when working with arrays
._forEach(
\.arrayOfElements, // non-identified
action: \.pathToAction,
element: { ElementReducer() }
)Labeled ForEach is useful for multiline ergonomics
forEach(
state: \.arrayOfElements,
action: \.pathToAction,
element: { ElementReducer() }
)
._forEach(
state: \.arrayOfElements, // non-identified
action: \.pathToAction,
element: { ElementReducer() }
)ComposableCocoa
[!NOTE]
The product is compatible with non-Apple platforms, however it uses conditional compilation, so APIs are only available on Apple platforms
ComposableCocoaView
CustomCocoaView that is also ComposableObjectProtocol
public class ExampleCocoaView: ComposableCocoaViewOf<ExampleFeature> {
// Initial configuration
override public func _init() {
super._init()
}
// Action example
func onTap() {
core.store?.send(.tap)
}
// Scoping
override public func scope(_ store: Store?) {
super.scope(store)
childView.core.setStore(store?.scope(
state: \.child.state,
action: \.child.action
))
}
// Binding
override public func bind(
_ store: Store,
into cancellables: Core.Cancellables
) {
super.bind(store, into: cancellables)
// This API is not yet available
store.observe(\.text)
.assign(to: label, \.text)
.store(in: cancellables)
}
}ComposableViewController
CustomCocoaViewController that is also ComposableObjectProtocol. Composable controllers won't scope/bind values untill managed object is loaded (view for ViewControllers, window for WindowControllers). API is similar to ComposableCocoaView.
ComposableTabViewControlleris also available oniOSComposableWindowControlleris available onmacOS
ComposableSwiftUI
[!NOTE]
The product is compatible with non-Apple platforms, however it uses conditional compilation, so APIs are only available on Apple platforms
ComposableView
Protocol for SwiftUI views that improves composability. Composable views can only be initialized with optional stores.
public struct ExampleView: ComposableView {
@UIBindable
private var store: StoreOf<ExampleFeature>
public init(_ store: StoreOf<ExampleFeature>) {
self.store = store
}
public var body: some View { /*...*/ }
}ComposableExtensions
Umbrella product that exports everything.
Installation
Basic
You can add composable-architecture-extensions to an Xcode project by adding it as a package dependency
- From the File menu, select Swift Packages › Add Package Dependency…
- Enter
"https://github.com/capturecontext/composable-architecture-extensions"into the package repository URL text field - Choose products you need to link to your project.
Recommended
If you use SwiftPM for your project structure, add composable-architecture-extensions dependency to your package file.
.package(
url: "https://github.com/capturecontext/composable-architecture-extensions.git",
.upToNextMinor("0.3.0-alpha.1")
)Do not forget about target dependencies:
.product(
name: "<#Product#>",
package: "composable-architecture-extensions"
)License
This library is released under the MIT license. See LICENSE for details.
Package Metadata
Repository: CaptureContext/composable-architecture-extensions
Stars: 9
Forks: 1
Open issues: 0
Default branch: main
Primary language: swift
License: MIT
Topics: cocoa, cocoatouch, composable-architecture, ios, macos, navigation, spm, swift, swiftpm, swiftui, tca, tvos, udf, uikit, watchos
README: README.md