Contents

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.

  • ComposableTabViewController is also available on iOS
  • ComposableWindowController is available on macOS

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

  1. From the File menu, select Swift Packages › Add Package Dependency…
  2. Enter "https://github.com/capturecontext/composable-architecture-extensions" into the package repository URL text field
  3. 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