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?