1

When building an application or program using the concepts of reactive programming, how does this work for nested reactive properties?

I have an example using Swift, ReactiveKit, and Bond, however the concepts apply to any reactive programming setup.

class User {
    var firstName: Observable<String>

    init(firstName: String) {
        self.firstName = Observable<String>(firstName)
    }
}

class ViewController: UIViewController {
    var user: Observable<User> = Observable<User>(User.init(firstName: "Bob"))
    @IBOutlet let label: UILabel!
    
    override func viewDidLoad() {
        user.firstName.bind(to: label)
    }

    @IBAction func updateUser() {
        WebService.retrieveUserFromServer { [weak self] user in
            self?.user.value = user
        }
    }
}

So in the example above, I want the label to be updated whenever the user or user.firstName is updated. But currently, if updateUser gets called, and a new user instance is passed in, the bind to the label doesn't work anymore.

So in this example, the firstName can be updated directly, or the entire user instance can be updated. Of course there is a way to maybe use some combine functions to add a listener for when user gets updated or user.firstName gets updated and handle it then. But that gets extremely messy very quickly, especially as you add more properties to User.

How are you supposed to handle these types of cases in reactive programming? Where you have a parent property that is reactive, and properties that are reactive within that class, and you want to react based on either the parent being updated, or any of the children properties being updated.

0

1 Answer 1

0

First, Observables should never be vars, they should only ever be lets. You don't want to reseat an Observable because that will break all the bindings.

Second, your code uses passive (rather than reactive) programming in the @IBAction. I use RxSwift/RxCocoa but I expect that Bond has a reactive wrapper around IBActions that you can use.

Third, retrieveUserFromServer should return an Observable rather than use a callback closure.

But none of the above addresses your fundamental question. How should one deal with nested Observables? In RxSwift, we use flatMap for this purpose. In Combine, the same behavior can be achieved with map/switchToLatest.

In RxSwift:

user
    .flatMapLatest { $0.firstName }
    .bind(to: label.rx.text)

In Combine:

user
    .map { $0.firstName }
    .switchToLatest()
    .sink { [label] value in
        label?.text = value
    }

I expect that ReactiveKit with Bond would look similar to one or both of the above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.