TL;DNR - Was replacing the Combine
Publisher
with an AsyncStream
considered?
In an ObservableObject
an @Published
is used to wrap your property into a publisher. This forces your code to depend on the Combine
framework and adds the limitations as mentioned by the author.
Isn't an AsyncStream
the modern concurrency equivalent of a combine publisher?
What about a StreamableObject
equivalent of ObservableObject
?
One whose parameters can be marked with @Streamed
instead of @Published
?
Then you could use an @StreamedObject
in place of an @ObservedObject
.
Was this considered? It seems like it would be the closest to a drop in replacement for Combine
to modern concurrency.
final class Model: StreamedObject {
@Streamed private var minutes = 1
@Streamed private var seconds = 0
var time: String {
String(format: "%.2ld:%.2ld", self.minutes, self.seconds)
}
func incrementMinutes() {
minutes += 1
}
}
struct ExampleView: View {
@StreamedObject var model = Model
var body: some View {
Text(model.time)
Button {
model.incrementMinutes()
} label: {
Text("Increment Minutes")
}
}
}
SwiftUI
would use the AsyncStream
under the hood to await changes, in the same way that it now uses publishers.
Outside of SwiftUI
you could observe the model changes using modern concurrency:
let model = Model()
for await time in model.$time {
print(time)
}
In short, the same goals when using ObservableObject
, @ObservedObject
, and @Published
would be accomplished by using an AsyncStream
instead of a Combine.Publisher
. (Thereby removing the dependency on the Combine
framework)
StreamableObject
would use a continuation for objectWillChange
instead of how an ObservableObject
uses a publisher.
And the @Streamed
would use an AsyncStream
as its projected value similar to how the @Published
uses a Publisher
.
All current functionality and familiar patterns would remain. The solution would just no longer use publishers "under the hood".
The model.time property would trigger a UI update in exactly the same way as it would with an @Published
on and ObservableObject
.
Just wondering if this was considered. Maybe this is too small scope of a change?