Swift package

composable-architecture-extensions

Optional-store lifecycle and Cocoa integration for the Composable Architecture

Let reusable components exist before their logic

Some Cocoa objects and views need a long-lived identity even when their feature store is not available yet. ComposableCore owns an optional store and defines the lifecycle for attaching, replacing, scoping, binding, and releasing it.

@MainActor
final class SearchCoordinator:
  ComposableObjectOf<SearchFeature> {

  override func scope(_ store: Store?) {
    super.scope(store)
    results.core.setStore(
      store?.scope(
        state: \.results,
        action: \.results
      )
    )
  }

  override func bind(
    _ store: Store,
    into cancellables: Core.Cancellables
  ) {
    super.bind(store, into: cancellables)
    // Install store observation here.
  }
}

setStore(_:) accepts both ordinary and optional-state stores; releaseStore() tears the connection down. Cancellables belong to the supplied lifecycle container and are cleared when the store changes.

Bring the same lifecycle to Cocoa

ComposableCocoaViewOf, ComposableViewControllerOf, and the macOS ComposableWindowControllerOf combine that core with reusable UI bases. Controllers defer binding until their managed view or window loads, so attaching logic does not force UI construction.

Choose ComposableCore, ComposableCocoa, or ComposableSwiftUI independently. Use the ComposableExtensions umbrella only when a target intentionally needs every surface, and keep reducer/domain conventions in the project’s primary TCA layer.

Lifecycle APIResponsibility
setStore(_:)Attach or replace ordinary and optional-state stores
scope(_:)Derive and pass stores to child components
bind(_:into:)Install observation owned by the current store lifecycle
storeWillSet / storeDidSetHandle transition-specific work only
releaseStore()Disconnect logic and clear lifecycle cancellables

Choose ComposableObjectOf for plain long-lived objects, ComposableNSObjectOf for Objective-C identity, and the Cocoa view or controller aliases for UI. Send actions through core.store?.send(...); prefer the supplied keyed or unkeyed cancellable storage over deprecated Set<AnyCancellable> hooks.