It's a common mistake to expect that a @Published
property's value has been updated when .sink()
block is executed. In that case however, the property still has the old value, because .sink()
is triggered by willSet
(as is explained here).
Some suggest, for example here, that adding .receive(on:)
solves this issue.
But, I've also read somewhere, that adding .receive(on:)
, is not a fundamental fix. This makes me think that it may still fail under certain conditions.
So, my question is: Does adding .receive(on:)
guarantee that the .sink()
block will be executed after the property's value has actually been set (and didSet
has been called)?
Here's some code from referenced example video above. Without the .receive(on:)
, the table does not show the new ["One", "Two", "Three"]
content after addItems()
is called; although the .sink()
block is executed.
override func viewDidLoad()
{
super.viewDidLoad()
viewModel.$dataSource
.receive(on: RunLoop.main) <<=== 'fixes' issue
.sink(receiveValue:
{ [weak self] _ in
self?.tableView.reloadData()
})
}
@IBAction func addItems()
{
viewModel.dataSource = ["One", "Two", "Three"]
}
As an encore, here's a sightly related answer from @robmayoff about which scheduler to use; another commonly misunderstood subject.