Releases: pointfreeco/swift-composable-architecture
0.25.1
- Fixed: a regression introduced in 0.25.0, where
TestStore
failures were no longer printed in a proportional diff format, has been addressed. - Fixed: removed a redundant conformance (thanks @aroben).
- Infrastructure: the Composable Architecture's test suite now uses
XCTAssertNoDifference
instead ofXCTAssertEqual
.
0.25.0
- Added: the Composable Architecture now uses Custom Dump for its debugging and testing tools. This library improves upon the original debugging/diffing tools that came with earlier versions of the Composable Architecture by collapsing unchanged parts of the diff, and more.
- Added: a French translation of the README (thanks @nikitamounier).
- Changed:
ViewStore.suspend(while:)
now uses Combine's async/await tools under the hood (thanks @iampatbrown for further cleanup). - Changed:
Reducer.optional
and other methods that tookfile
andline
parameters previously took them as unnamed arguments. They have been updated to takefile
andline
as named arguments. - Infrastructure: refactored Tic-Tac-Toe to better model the board's domain with a nested
Three
data type.
0.24.0
-
Added:
Effect.task
, for wrapping async/await work in an effect.Effect.task { guard case let .some((data, _)) = try? await URLSession.shared .data(from: .init(string: "http://numbersapi.com/42")!) else { return "Could not load" } return String(decoding: data, as: UTF8.self) }
-
Added: an
Effect.catchToEffect
overload that takes a transform function, avoiding the need for an extramap
(thanks @eimantas).// before: return environment.apiClient.fetch() .catchToEffect() .map(MyAction.apiResponse) // after: return environment.apiClient.fetch() .catchToEffect(MyAction.apiResponse)
-
Added:
Effect.cancel(ids:)
, which can cancel multiple effects at once by taking multiple cancel identifiers.return .cancel(ids: OnAppearId(), ApiRequestId())
-
Added: Alert and action sheet helpers (
AlertState
andActionSheetState
) can now be configured with animated button actions (thanks @fonkadelic).Support comes with a slightly new API and a deprecation (read: breaking change) of the old API:
// before: primaryButton: .destructive(TextState("Delete"), send: .deleteButtonTapped), // after: primaryButton: .destructive(TextState("Delete"), action: .send(.deleteButtonTapped)),
The newer API comes with an overloaded
animation
parameter, for specifying an animation for the action when sent back to the reducer:primaryButton: .destructive( TextState("Delete"), action: .send(.deleteButtonTapped, animation: .default) ),
-
Added: Alert and action sheet helpers for UIKit (thanks @andreyz).
class MyViewController: UIViewController { let store: Store<MyState, MyAction> let viewStore: ViewStore<MyState, MyAction> private var cancellables: Set<AnyCancellable> = [] private weak var alertController: UIAlertController? ... func viewDidLoad() { ... self.viewStore.publisher .alert .sink { [weak self] alert in guard let self = self else { return } if let alert = alert { let alertController = UIAlertController(state: alert, send: { self.viewStore.send(.settings($0)) }) self.present(alertController, animated: true, completion: nil) self.alertController = alertController } else { self.alertController?.dismiss(animated: true, completion: nil) self.alertController = nil } } .store(in: &cancellables) } }
-
Updated:
WithViewStore.debug()
now prints a diff of view state whenever its body is evaluated. This can be used to determine what change to what portion of sub-state was responsible for the evaluation. -
Updated: code that prints file debug information uses
#fileID
now instead of#file
to reduce debug noise. -
Fixed:
Effect.throttle
should now clean up old values being debounced in itslatest: false
strategy, preventing the occasional old value from emitting (thanks @p4checo). -
Fixed:
Effect.debounce
should now always deliver on the scheduler it is provided. -
Fixed: A minimum deployment target of macOS 11 should now compile without error (thanks @aroben).
-
Infrastructure: Improved
ViewStore.publisher
documentation. -
Infrastructure: Added an Italian translation of the README (thanks @Bellaposa).
-
Infrastructure: Added a SwiftUI case study for focus state.
-
Infrastructure: The Tic-Tac-Toe demo has been modernized. It now uses SPM for modularization instead of frameworks.
-
Infrastructure: Some cleanup and modernization of demo code.
0.23.0
- Added: support for concurrency-powered APIs like SwiftUI's
View.refreshable()
viaViewStore.send(_:while:)
andViewStore.suspend(while:)
, which will suspend the current task while a predicate is true. - Bug fixed:
IfLetStore
should never re-render its initial state when its state goesnil
(thanks @ollitapa). - Bug fixed:
Effect.throttle
is now synchronized, eliminating potential data races (thanks @p4checo). - Infrastructure: documentation cleanup (thanks @konomae).
0.22.0
- Added:
Effect.throttle
can throttle how often its associated action is fed back into the reducer (thanks @kerryknight). - Regression fixed: A change in 0.21.0 that prevented store publishers from emitting actions if their view stores were deinitialized. This mainly affected UIKit apps.
- Regression fixed: A change in 0.20.0 that could leave an action buffered in the store and emit late (thanks @heyltsjay).
0.21.0
- Changed: the Composable Architecture now depends on Identified Collections for
IdentifiedArray
, which has been rewritten for correctness and performance. There are some breaking changes, which are documented in its release. - Changed: support for Swift 5.1 and 5.2 has been dropped. Please use Swift 5.3 (Xcode 12) or later, or this is of course a breaking change, and you must lock your application to swift-composable-architecture 0.20.0 or earlier.
- Changed:
Reducer.binding
now takes an extract function, not a case path. Case path expressions can still be used, meaning existing uses should generally continue to compile. If you were passing a concreteCasePath
value, this is a breaking change, and you can pass along theCasePath.extract(from:)
method, instead. - Changed:
TestStore
has relaxed itsEquatable
constraint onAction
. It is only required for whenTestStore.receive
s actions from effects. - Performance improved: view stores now perform the minimum number of equality checks necessary (thanks @iampatbrown).
- Fixed:
ViewStore.publisher
now emits the current store state, and not the previous state (thanks @maximkrouk, @iampatbrown). - Infrastructure: cleaned up recursive case study, web socket case study; added benchmarking target.
0.20.0
- Added:
Effect.deferred()
, for delaying the execution of an effect by a given time (compare toPublisher.delay()
, which delays merely the delivery of some work that has already been performed). Thanks, @wendyliga. - Updated:
SwitchStore
now supports up to 9CaseLet
views. - Performance improvement/fix: the number of times
Store.scope
's state transform function has been minimized. Previously it was evaluated an extra time, multiplied by downstream scopes. - Performance improvement/fix: the number of times
ViewStore
's duplicate check has been reduced. - Performance improvement/fix: a store publisher will only emit a single state change per synchronous
Store.send
and asynchronous effect received. This means synchronous effects (returned immediately from a reducer viaEffect.init(value:)
) will no longer result in extra publisher emissions. This is a breaking change if your application previously depended on each of these emissions. Workaround: usePublisher.receive(on:)
to schedule these effects on the next run loop tick. - Infrastructure: cleaned up demo apps and documentation; added an Indonesian translation of the README (thanks @wendyliga).
0.19.0
- Added: a new overload of
Reducer.pullback
for working with enum-based state. It uses a case path instead of a writable key path for extracting and embedding state for a particular enum case. - Added: a new
SwitchStore
view for converting stores on enum state into stores on individual enum cases (thanks @lukeredpath for sketching out the original implementation). - Changed:
Effect.timer
now callscancelInFlight: true
under the hood to automatically cancel any in-flight timers with the same cancellable id (thanks @dannyhertz). If you rely on the existing behavior, which allows for timers to interleave and stack on one another, this is a breaking change and you must manually create your timers usingPublishers.Timer
instead before upgrading. - Fixed:
ForEachStore
has been optimized and a crash related to removing rows has been fixed. - Fixed: documentation cleanup.
- Infrastructure: modernized example/demo code, along with assorted fixes (thanks @yimajo, @filblue).
0.18.0
- Updated:
IfLetStore
andForEachStore
closures are now view builders. - Changed:
IfLetStore
's optionalelse
branch now takes a view builder closure. The overload that takes anelse
view directly has been deprecated. - Fixed: A bug in iOS 13's Combine can cause uses of the
Fail
publisher to crash. We have updatedEffect.init(error:)
to not useFail
under the hood and avoid this crash. - Fixed: A crash related to behavior in SwiftUI's
ForEach
has been fixed, where theIdentifiedArray
version ofForEachStore
would unsafely unwrap elements after removal. - Improved: documentation for
Store.ifLet
(thanks @mluisbrown). - Infrastructure: improve UIKit demo support of dark mode (thanks @hungtruong).
0.17.0
- Added:
Effect.failing
, an effect that will cause an XCTest assertion failure if it is subscribed to. - Added: A new
ViewStore
convenience initializer forVoid
state (thanks @siejkowski). - Changed: The
fireAndForget()
method is now more permissive. It will now ignore all output and failure for you before upcasting the output and failure types to any type. - Changed:
TextState
now has a custom debug output format for easier debugging. - Infrastructure: various documentation improvements and fixes for TicTacToe.