The big theme of 0.4.0 is collapsing the effect pipeline onto MainActor and tightening the concurrency contract. The store no longer owns a lock, an actor, or a driver task — isolation alone provides ordering. As a side effect, Send is now properly async.
Breaking changes
-
Sendis nowasync. Inside.runeffect bodies you mustawait send(.action). Callers no longer spawn a Task per dispatch; theawaithops to MainActor and returns when the dispatch is complete.// before return .run { send in let data = await fetchData() send(.updateData(data)) } // after return .run { send in let data = await fetchData() await send(.updateData(data)) }
-
@Shared.wrappedValueis read-only. The setter was unused and only created the illusion that you could rebind a shared store. For test-time overrides, useStoreValues.withValues { ... }instead. -
Effect pipeline is fully MainActor-isolated.
.runregister/cancel and.cancel(id:)now happen synchronously on MainActor, so a cancel dispatched in the samesendchain as a.cancellable(id:)is guaranteed to observe its registration. The internal driver actor and lock are gone.
Fixed
.animation(nil)now actually clears any attached animation.- Persistence no longer wipes stored data on encode/decode failure — the blob is preserved so a future migration can read it.
Store.cancel(id:)logs on miss instead of silently no-oping.- Eliminated a register/cancel race in the effect lifecycle.
Concurrency & tooling
- Single
Package.swiftwithswiftLanguageModes: [.v6]. - Swift 7 upcoming features enabled across all targets (
ExistentialAny,InternalImportsByDefault,MemberImportVisibility,InferIsolatedConformances,NonisolatedNonsendingByDefault). - Bumped
swift-syntaxto603.0.1for Swift 6.2 toolchains.
Internal
Store.tasksis nowprivate(set).KeyPathresolution routes throughStoreValues.current(_:).- Dropped redundant lock in
StoreValues— MainActor isolation is enough. - Removed empty
deinitand clarifiedwillSaveis internal Storable plumbing.
Docs
- Full README rewrite against the 0.4.0 API.
@Injectdocblock spells out the expansion contract and the__Store_<name>peer naming.- Binding capture policy (strong getter / weak setter) documented and pinned with regression tests.
CI
- GitHub Actions workflow:
swift build+swift testonmacos-26for every PR and push tomaster.
Tests
- SwiftUI rendering baseline using real hosted views, plus negative-invariant coverage.
- Coverage for previously untested public API surfaces.
- Cleaned up flaky
Task.sleep-based waits.
Full Changelog: 0.3.2...0.4.0