In SwiftUI, can you use an instance of a Publisher
directly as an @ObjectBinding
property or do you have to wrap it in a class that implements BindableObject
?
let subject = PassthroughSubject<Void, Never>()
let view = ContentView(data:subject)
struct ContentView : View {
@ObjectBinding var data:AnyPublisher<Void, Never>
}
// When I want to refresh the view, I can just call:
subject.send(())
This doesn't compile for me and just hangs Xcode 11 Beta 2. But should you even be allowed to do this?
In SwiftUI, you can create bindings in 2 ways: With the @Binding property wrapper, which creates a binding, but doesn't store it. With other property wrappers, like @State, which creates a binding, and also stores its value.
String in swift is a value type, so your textValue property is taking a copy of the value, and SwiftUI is monitoring that copy, not the actual value in Controller.message . What you want here is a binding or an observed object—exactly which depends on whether Controller is a struct or a class type.
In your View body use .onReceive
passing in the publisher like the example below, taken from Data Flow Through SwiftUI - WWDC 2019 @ 21:23. Inside the closure you update an @State var, which in turn is referenced somewhere else in the body which causes body to be called when it is changed.
You can implement a BindableObject
wich takes a publisher as initializer parameter.
And extend Publisher
with a convenience function to create this BindableObject
.
class BindableObjectPublisher<PublisherType: Publisher>: BindableObject where PublisherType.Failure == Never {
typealias Data = PublisherType.Output
var didChange: PublisherType
var data: Data?
init(didChange: PublisherType) {
self.didChange = didChange
_ = didChange.sink { (value) in
self.data = value
}
}
}
extension Publisher where Failure == Never {
func bindableObject() -> BindableObjectPublisher<Self> {
return BindableObjectPublisher(didChange: self)
}
}
struct ContentView : View {
@ObjectBinding var binding = Publishers.Just("test").bindableObject()
var body: some View {
Text(binding.data ?? "Empty")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With