Archdoog/ObservationsKit
Tools to start sooner with Swift Observation
ObservationShim
This is a copy of SwiftLang's Observations.swift with some small tweaks to enable iOS 17+ compatibility. There are endless online discussions and dozens of projects that aim to enable the use of AsyncSequence and modern concurrency based streaming tools in favor of Combine. This one clicked thanks to this Swift Forums post iOS 18 support for the Observations struct is being dropped before release?.
[!IMPORTANT] This is not aimed at replacing
Observations. It's simply a shim you can use to start making real use of the Apple Observations framework in favor of a bunch of bridges to other data sources likeCombine
This example shows how you'd effectively erase the official and shimmed backport into an AsyncStream to use outside of SwiftUI. Note Pointfree Co's ConcurrencyExtras was used to allow erasure into a clean AsyncStream<Element>.
func observe<Element: Sendable>(
@_inheritActorContext _ emit: @escaping @isolated(any) @Sendable () -> Element,
) -> AsyncStream<Element> {
if #available(iOS 26.0, macOS 26.0, tvOS 26.0, watchOS 26.0,visionOS 26.0, *) {
let official = Observations(emit)
return AsyncStream(official)
} else {
let backport = ObservationsShim(emit)
return AsyncStream(backport)
}
}References
ObservationTesting
Swift Testing introduced a new paradigm for async confirmation in Testing asyncronous code. The swift tools are totally acceptable, but can be quite verbose and a bit tricky, especially testing outputs from AsyncSequences. The ObservationTesting library enables concise unit tests for AsyncSequences. This also works really well with Observations and ObservationsShim.
This includes verifying Equatable elements over time.
@Test("A value is emitted from the stream")
func basic() async throws {
let stream = AsyncStream { continuation in
continuation.yield("cats")
continuation.yield("dogs")
continuation.yield("lizards")
}
try await stream.fulfillment(of: "cats", "dogs", "lizards")
}Or complex conditions that can't easily be represented as expected value(s).
@Test("A condition is verified on the stream")
func conditionMet() async throws {
let stream = AsyncStream { continuation in
continuation.yield("cats")
}
try await stream.fulfillment { value in
value == "cats"
}
}Package Metadata
Repository: Archdoog/ObservationsKit
Stars: 0
Forks: 0
Open issues: 0
Default branch: main
Primary language: swift
License: Other
Topics: asyncsequence, swift, swift-observation, swift-testing
README: README.md