Add variadic generics version of `Defaults.updates()` (#191)
This commit is contained in:
parent
1f693cde80
commit
a89f799930
|
@ -292,13 +292,64 @@ extension Defaults {
|
|||
}
|
||||
}
|
||||
|
||||
// We still keep this as it can be useful to pass a dynamic array of keys.
|
||||
/**
|
||||
Observe updates to multiple stored values.
|
||||
|
||||
- Parameter keys: The keys to observe updates from.
|
||||
- Parameter initial: Trigger an initial event on creation. This can be useful for setting default values on controls.
|
||||
|
||||
```swift
|
||||
Task {
|
||||
for await (foo, bar) in Defaults.updates([.foo, .bar]) {
|
||||
print("Values changed:", foo, bar)
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
public static func updates<each Value: Serializable>(
|
||||
_ keys: repeat Key<each Value>,
|
||||
initial: Bool = true
|
||||
) -> AsyncStream<(repeat each Value)> {
|
||||
.init { continuation in
|
||||
func getCurrentValues() -> (repeat each Value) {
|
||||
(repeat self[each keys])
|
||||
}
|
||||
|
||||
var observations = [DefaultsObservation]()
|
||||
|
||||
if initial {
|
||||
continuation.yield(getCurrentValues())
|
||||
}
|
||||
|
||||
for key in repeat (each keys) {
|
||||
let observation = DefaultsObservation(object: key.suite, key: key.name) { _, _ in
|
||||
continuation.yield(getCurrentValues())
|
||||
}
|
||||
|
||||
observation.start(options: [])
|
||||
observations.append(observation)
|
||||
}
|
||||
|
||||
let immutableObservations = observations
|
||||
|
||||
continuation.onTermination = { _ in
|
||||
// `invalidate()` should be thread-safe, but it is not in practice.
|
||||
DispatchQueue.main.async {
|
||||
for observation in immutableObservations {
|
||||
observation.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We still keep this as it can be useful to pass a dynamic array of keys.
|
||||
/**
|
||||
Observe updates to multiple stored values without receiving the values.
|
||||
|
||||
- Parameter keys: The keys to observe updates from.
|
||||
- Parameter initial: Trigger an initial event on creation. This can be useful for setting default values on controls.
|
||||
|
||||
```swift
|
||||
Task {
|
||||
for await _ in Defaults.updates([.foo, .bar]) {
|
||||
|
@ -307,7 +358,7 @@ extension Defaults {
|
|||
}
|
||||
```
|
||||
|
||||
- Note: This does not include which of the values changed. Use ``Defaults/updates(_:initial:)-88orv`` if you need that. You could use [`merge`](https://github.com/apple/swift-async-algorithms/blob/main/Sources/AsyncAlgorithms/AsyncAlgorithms.docc/Guides/Merge.md) to merge them into a single sequence.
|
||||
- Note: This does not include which of the values changed. Use ``Defaults/updates(_:initial:)-l03o`` if you need that.
|
||||
*/
|
||||
public static func updates(
|
||||
_ keys: [_AnyKey],
|
||||
|
|
|
@ -52,6 +52,7 @@ typealias Default = _Default
|
|||
### Methods
|
||||
|
||||
- ``Defaults/updates(_:initial:)-88orv``
|
||||
- ``Defaults/updates(_:initial:)-l03o``
|
||||
- ``Defaults/updates(_:initial:)-1mqkb``
|
||||
- ``Defaults/reset(_:)-7jv5v``
|
||||
- ``Defaults/reset(_:)-7es1e``
|
||||
|
|
|
@ -581,6 +581,34 @@ final class DefaultsTests {
|
|||
let count = await counter.count
|
||||
#expect(count == 2)
|
||||
}
|
||||
|
||||
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, visionOS 1.0, *)
|
||||
@Test
|
||||
func testUpdatesMultipleKeysVariadic() async {
|
||||
let key1 = Defaults.Key<Bool>("updatesMultipleKeyVariadic1", default: false, suite: suite_)
|
||||
let key2 = Defaults.Key<Bool>("updatesMultipleKeyVariadic2", default: false, suite: suite_)
|
||||
let counter = Counter()
|
||||
|
||||
async let waiter: Void = {
|
||||
for await (_, _) in Defaults.updates(key1, key2, initial: false) {
|
||||
await counter.increment()
|
||||
|
||||
if await counter.count == 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
try? await Task.sleep(for: .seconds(0.1))
|
||||
|
||||
Defaults[key1] = true
|
||||
Defaults[key2] = true
|
||||
|
||||
await waiter
|
||||
|
||||
let count = await counter.count
|
||||
#expect(count == 2)
|
||||
}
|
||||
}
|
||||
|
||||
actor Counter {
|
||||
|
|
Loading…
Reference in New Issue