Issue:
I am using a Publisher in a code example which I wrote based on the code example here, [https://developer.apple.com/documentation/combine/observableobject][1]. I expect the print statement inside the body of the sink.receive() to print "received value 30" when I run the code sample below followed by "received value 31". What is happening instead is that the console is printing "received value ()" then "asaad has birthday ()".
Why is this? How can I fix it?
Code:
import Combine
class Contact: ObservableObject {
@Published var name: String
@Published var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func hasBirthday() {
age += 1
}
}
var cancellable: AnyCancellable!
let asaad = Contact(name: "Asaad Jaber", age: 30)
cancellable = asaad.objectWillChange
.sink(receiveValue: { value in
print("received value \(value)")
})
let hasBirthday = asaad.hasBirthday()
print("asaad has birthday \(hasBirthday)")
Steps to Reproduce:
You are listening on the object itself and that it changed, not on the value that you want to observe changes on. You could change your code to the following:
cancellable = asaad.$age //<-- listen to the publisher of age
.sink(receiveValue: { value in
print("received value \(value)")
})
Then you get updates whenever age changes and thus the value
will also be the new value of age
.
Edit: Explanation why the solution in your question does not work as you expect.
If you subscribe to changes of the entire object via objectWillChange
, you need to consider following points.
age
, there is an event. If you change name
, there is an event. That means: the event can't just also send the new value, because it wouldn't know what type that value has. Is it Int? A String? Any other custom type you implemented your own? Could be anything. (Also, say you have another Int
property called height
. If you just got any Int
value in the sink: you would not know "did the age just change or the height?")value
in the sink, you will also see: value is Void
. There's no further information attached. You only get to know that something on that object is about to change. Not what exactly will change.That's why it's better to listen to specific property publishers like $age
.
age
, the sink knows that it's observing changes of an Int
.sink
that knows "do this if the age changes". And on another property you will be able to define "do another thing when the the height changes." And so on.