I am setting up a sink
like so:
name.publisher
.removeDuplicates()
.receive(on: RunLoop.main)
.sink { [weak self] config in
guard let self = self else { return }
// this closure gets called right away at setup even though the @Published property `name` was already setup and did not change
}.store(in: &subscribers)
The property is declared like so in an observable object:
@Published var name:String = ""
So, I'm obviously missing something here. Why is sink called once at setup even though name
did not change? I can avoid this behavior by using the dropFirst()
operator but, I'd like to understand why the closure is always called once immediately after setup?
Why is that?
CodePudding user response:
Here's a playground that uses debugPrint
to show you what you get from name.publisher
:
import UIKit
import Combine
//Holds the score
class ViewModel : ObservableObject {
@Published var name = "0"
}
let viewModel = ViewModel()
debugPrint(viewModel.name.publisher)
What you get is
Combine.Publishers.Sequence<Swift.String, Swift.Never>(sequence: "0")
So you get a sequence publisher that has a single item, "0". It will publish that value once and the sequence will end. Each time a subscriber attaches to that sequence it will get all the items in the sequence (there's only one) and the end.
This is probably not what you want.
Instead I think you want to use $name
to access the published property:
import UIKit
import Combine
//Holds the score
class ViewModel : ObservableObject {
@Published var name = "0"
}
let viewModel = ViewModel()
let subscription = viewModel.$name.sink { print($0) }
viewModel.name = "Alex"
When you subscribe to the published property you will still get a posted event that is the current value of the property. However, by using $name
you are attaching to a stream that will send you the current value on subscription AND each subsequent value.