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:
- I clicked on Xcode in my dock to launch Xcode.
- I clicked File > New > Playground to create a new playground.
- I copied the code in the code example and pasted it in the playground and I modified some of the values.
- I clicked the Play button to execute the code.
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:
Then you get updates whenever age changes and thus the
valuewill also be the new value ofage.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 changename, 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 anotherIntproperty calledheight. If you just got anyIntvalue in the sink: you would not know "did the age just change or the height?")valuein the sink, you will also see: value isVoid. 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 anInt.sinkthat 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.