


AsyncValue
This is a simple package that provides a convenience property wrapper around AsyncStream that behaves almost identically to @Published
.
Installation
Via Xcode
- In the project navigator on the left, click on your project
- click
Package Dependencies
- enter: https://github.com/BrentMifsud/AsyncValue.git into the search bar
- select the desired version and click
Add Package
Via Package.swift
in your Package.swift
file, add the following:
let package = Package(
name: "MyPackage",
dependencies: [
.package(url: "https://github.com/BrentMifsud/AsyncValue.git", from: .init(1, 0, 0))
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "MyPackage",
targets: ["MyPackage"]
),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "MyPackage",
dependencies: ["AsyncValue"]
),
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage"]
),
]
)
Usage
Accessing the current value
@AsyncValue var myValue: String = "Test"
print(myValue) // prints: test
Observing changes to the value
Just like the publisher backing @Published
, AsyncValue
is backed by an AsyncStream. And you can subscribe to updates to the value.
@AsyncValue myValue: String = "Test"
Task {
for await value in myValue {
print("Value: \(value)")
}
}
Task {
await Task.sleep(nanoseconds: 1_000_000_000)
myValue = "New Value"
}
/* Prints:
Value: test
Value: New Value
*/
Observing with multiple tasks
One of the major limitations of AsyncStream out of the box is that you can only for-await-in
on it with a single task.
AsyncValue
does not have this limitation:
@AsyncValue myValue: String = "Test"
Task {
for await value in myValue {
print("Task 1 Value: \(value)")
}
}
Task {
for await value in myValue {
print("Task 2 Value: \(value)")
}
}
Task {
await Task.sleep(nanoseconds: 1_000_000_000)
myValue = "New Value"
}
/* Prints (note that the order of the tasks printing may vary as this is happening asyncronously):
Task 1 Value: test
Task 2 Value: test
Task 2 Value: New Value
Task 1 Value: New Value
*/
Using with SwiftUI
ObservableObject support
AsyncValue
can be adapted to work seamlessly with ObservableObject
with a single line of code:
class MyObservableObject: ObservableObject {
@AsyncValue var myValue: String = "Test"
}
Any changes to an AsyncValue
will trigger a view update in the same way @Published
does.
Thanks to jlsiewert for coming up with the cool trick for making this work automatically.
.onReceive equivalent for AsyncSequence
There is also an .onRecieve(sequence:perform:)
view modifier that allows you to respond to changes from any AsyncSequence.
struct MyView: View {
var body: some View {
Text("Hello World!")
.onReceive(myService.$myValue) { value in
print("The value changed to: \(value)")
}
}
}
class MyService: ObservableObject {
@AsyncValue var myValue: String = "Test"
}
AsyncValue
This is a simple package that provides a convenience property wrapper around AsyncStream that behaves almost identically to
@Published
.Installation
Via Xcode
Package Dependencies
Add Package
Via Package.swift
in your
Package.swift
file, add the following:Usage
Accessing the current value
Observing changes to the value
Just like the publisher backing
@Published
,AsyncValue
is backed by an AsyncStream. And you can subscribe to updates to the value.Observing with multiple tasks
One of the major limitations of AsyncStream out of the box is that you can only
for-await-in
on it with a single task.AsyncValue
does not have this limitation:Using with SwiftUI
ObservableObject support
AsyncValue
can be adapted to work seamlessly withObservableObject
with a single line of code:Any changes to an
AsyncValue
will trigger a view update in the same way@Published
does.Thanks to jlsiewert for coming up with the cool trick for making this work automatically.
.onReceive equivalent for
AsyncSequence
There is also an
.onRecieve(sequence:perform:)
view modifier that allows you to respond to changes from any AsyncSequence.