I'm messing around with Combine code and Swift UI and came across this problem. Effectively I want to pass a Publisher
into a View
and have that View
update every time the publisher publishes an update.
Here's a sample playground that will not compile. Instead it puts up an error - Escaping closure captures mutating 'self' parameter
on the .sink(...
line.
import Combine
import SwiftUI
struct MyView: View {
let cancellable: AnyCancellable
@State var current: Int = 0
init<P>(publisher: P) where P: Publisher, P.Output == Int, P.Failure == Never {
cancellable = publisher.sink { value in
self.current = value
}
}
var body: some View {
Text("\(current)")
}
}
let subject = PassthroughSubject<Int, Never>()
let x = MyView(publisher: subject)
subject.send(5)
Currently I've changed the code to use an ObservableObject
view model with the value inside it and telling that object to send an update. But I'm interested how others have gotten around this problem as I'd like a none view model option too.
What have you guys done?
You can use onReceive
to subscribe to Combine Publisher
s in SwiftUI View
s. That way the SwiftUI runtime will manage the subscription for you, even while your view may be recreated many times.
struct MyView: View {
@State var current: Int = 0
var body: some View {
Text("\(current)")
.onReceive(somePublisher) { self.current = $0 }
}
}
However, using ObservableObject
s directly is often a better idea, as they integrate directly into SwiftUI.
Currently I'm doing something like this:
import Combine
import SwiftUI
import PlaygroundSupport
class Model: ObservableObject {
var current: Int = 0 {
willSet {
self.objectWillChange.send()
}
}
}
struct MyView: View {
@EnvironmentObject var model: Model
var body: some View {
Text("\(model.current)")
}
}
let model = Model()
let myView = MyView().environmentObject(model)
PlaygroundPage.current.liveView = UIHostingController(rootView: myView)
model.current = 5
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.