RxSwift : manage object updates in the app

2019-08-28 05:43发布

I have a big concern about how to manage object properties changes.

Imagine I have a "car" class, with some properties like "name", "date", "price" etc.

In my view "A", I'm displaying all cars I retrieve from a API. In a view B & C, I can display and edit specific information about the car selected in the view A (let's say it's "car AAA"). it's possible too, to refresh the car object with a API call to retrieve the last information about the car.

I want to be able to update the view A, if the user does something on the object car in another view. Or, if the user "refreshed" the car object to be sure to have the last data about this car. But if the user just changed the name of the car, I don't want to refresh all the UI in the view A just for that.. I want to know that just the name has changed.

What is the best way to catch any update for this car in the view A? Do I have to have a class which manage all properties of the car as "PublishRelay" or "PublishSubject", and play with this in my full app?

1条回答
在下西门庆
2楼-- · 2019-08-28 06:43

I have a big concern about how to manage object properties changes.

Keep in mind that ReactiveX is a functional paradigm. The properties of objects don't change. Rather a new object is emitted from the Observable with different properties.

If you are only interested in tracking the name of a specific car then it's a simple mapping:

extension ObservableType where E == [Car] {
    func nameOfCar(withID id: Int) -> Observable<String?> {
        return map { $0.first(where: { $0.id == id }) }
            .map { $0?.name }
            .distinctUntilChanged()
    }
}

Because of the distinctUntilChanged() operator, the above will only emit a value if the car with the entered ID's name changes. The optional is there so the consumer can detect if the car is no longer in the array. More technically, this operator observes a Stream that emits arrays of cars, maps over each array emitted to see if the car with the correct ID exists, and if it does, finds that car's name. Then it compares that name with the previous name it emitted and emits the name only if it is different.

You can observe Car objects more generally with this:

extension ObservableType where E == Car {
    var name: Observable<String> {
        return map { $0.name }
            .distinctUntilChanged()
    }

    var price: Observable<Double> {
        return map { $0.price }
            .distinctUntilChanged()
    }

    // etc...
}

extension ObservableType where E == [Car] {
    func car(withID id: Int) -> Observable<Car?> {
        return map { $0.first(where: { $0.id == id }) }
            .distinctUntilChanged() // assumes a Car is Equatable
    }
}

I expect a more generic solution could be made with Swift's new key path system.

查看更多
登录 后发表回答