Consider the below Observable Object.
class User: ObservableObject {
@Published var age: Int
@Published var name: String {
didSet {
objectWillChange.send()
}
}
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
The below code prints blank value or Void block. Any reason why? If we change Integer value age it should simply print that value.
let userJohnCancellable = userJohn.objectWillChange.sink { val in
print("Changed Value \(val)")
}
userJohn.age = 21
userJohn.age = 39
We can try to print the values in the closure using userJohn.age
. But why does val not return a Integer value in this case.
Also what would be the best way to handle sink
changes for age and name, both, one is String other is Int.
You seem to be confused about ObservableObject. It is for use with SwiftUI. But your code is not SwiftUI code, so you don't need ObservableObject and you really can't use it in any meaningful way. If the goal is to be able to subscribe to the properties of User so as to be notified when one of them changes, then it suffices to make those properties Published:
class User {
@Published var age: Int
@Published var name: String
init(age: Int, name: String) {
self.age = age; self.name = name
}
}
Here's an example of using it; I will assume we have a user
property of a UIViewController:
class ViewController: UIViewController {
var cancellables = Set<AnyCancellable>()
var user = User(age: 20, name: "Bill")
override func viewDidLoad() {
super.viewDidLoad()
user.$age.sink {print("age:", $0)}.store(in: &cancellables)
user.$name.sink {print("name:", $0)}.store(in: &cancellables)
}
}
If this view controller's user
has its age
or name
changed, you'll see the print
output in the console.
If the question is how to handle both changes in a single pipeline, they have different types, as you observe, so you'd need to define a union so that both types can come down the same pipeline:
class User {
@Published var age: Int
@Published var name: String
enum Union {
case age(Int)
case name(String)
}
var unionPublisher: AnyPublisher<Union, Never>?
init(age: Int, name: String) {
self.age = age; self.name = name
let ageToUnion = $age.map { Union.age($0) }
let nameToUnion = $name.map { Union.name($0) }
unionPublisher = ageToUnion.merge(with: nameToUnion).eraseToAnyPublisher()
}
}
And again, here's an example of using it:
class ViewController: UIViewController {
var cancellables = Set<AnyCancellable>()
var user = User(age: 20, name: "Bill")
override func viewDidLoad() {
super.viewDidLoad()
user.unionPublisher?.sink { union in
switch union {
case .age(let age): print ("age", age)
case .name(let name): print ("name", name)
}
}.store(in: &cancellables)
}
}
Again, change the user
property's name
or age
and you'll get an appropriate message in the console.