Is this a bug in the @Published property wrapper or am I expecting a different behavior because I've misunderstood something fundamental?
Given:
import Combine
class Test {
@Published var value = 0
var valuePublisher: AnyPublisher<Int, Never> {
$value.eraseToAnyPublisher()
}
}
let t = Test()
let s = t.valuePublisher.sink { value in
print("closure value: \(value)")
print("object value: \(t.value)")
}
t.value = 42
I would expect that the object's value itself would be updated before publishing the change to its subscribers such that inside of sink the value is the same as the object's value. Is that expectation wrong?
What happens if you you assign a second time? If it then prints 42, then it‘s a willSet instead of a didSet event. However if it‘s still 0 then I have no idea and it feels like a bug.
Actually that should be unrelated. IIRC Published always emitted the latest value through its publisher.
You can imagine the internals to be more like this:
set {
// will set
outerSelf.objectWillChange.send()
// did set that pushes the value through the publisher
outerSelf[keyPath: wrapperKeyPath].storage = newValue
}
But the question is, where it's emitted, if you access the value itself, will it be the same as the emitted value? (According to the example above, no.) If not, should it be?
But now I'm curious because I'm struggling to understand why receiving on the main queue would alter that behavior? I think I need to re-read that thread.
Are you testing it with a beta device like mentioned in the thread? If not then it works because internally it still uses async which causes the publisher to emit after the property is truly set. However this is still not didSet semantic.