Reimond Hill
Reimond Hill

Reputation: 4760

Observable.CombineLatest bind and subscribe RxSwift

I am working on an app that uses an API that have some inconsistencies, I have achieved a result with these 2 observables that perform some shared actions but the first one 'servers' is an array that binds to the UITableView.

    serversViewModel.servers
        .asObservable()
        .observeOn(MainScheduler.instance)
        .bind(to: serversTableView.rx.items(cellIdentifier: ServersTableViewCell.identifier, cellType: ServersTableViewCell.self)) { [weak self] (row, element, cell) in

            guard let strongSelf = self else { return }
            cell.serverProxy.accept(element)
            if let currentServer = strongSelf.serversViewModel.currentServer.value,
                element == currentServer,
                let index = strongSelf.serversViewModel.servers.value.firstIndex(where: { $0 == currentServer }){

                strongSelf.serversTableView.selectRow(at: IndexPath(row: index, section: 0), animated: true, scrollPosition: .top)

            }

        }
        .disposed(by: disposeBag)

    serversViewModel.currentServer
        .asObservable()
        .observeOn(MainScheduler.instance)
        .subscribe(onNext: { [weak self] (server) in

            guard let strongSelf = self else { return }
            if let server = server, let index = strongSelf.serversViewModel.servers.value.firstIndex(where: { $0 == server }){
                strongSelf.serversTableView.selectRow(at: IndexPath(row: index, section: 0), animated: true, scrollPosition: .top)
            }
            else{
                strongSelf.serversTableView.deselectAllItems(animated: false)
            }

        })
        .disposed(by: disposeBag)

Is it possible to create a combined observable for both and use it for binding the UITableView?

Thank you

Upvotes: 1

Views: 3108

Answers (3)

Evan Anger
Evan Anger

Reputation: 714

I'd approach from a slightly different way. First I would consider pulling the combine observable back into the ViewModel you have already structured. No need for this composition to be in your ViewController.

Then output that composed signal to bind into your rx.items. You can wrap your objects will a table cell view model to control whether to show them in a 'selected state'

Then also output the currentServer from your viewModel to simply scroll to it.

Upvotes: 1

Daniel T.
Daniel T.

Reputation: 33979

You want to use combineLatest. Note that most of this should actually be in your view model...

In the below code, the servers constant is a tuple of both the array of Server objects that should be displayed and the index path of the current server. Whenever either emits a new value, servers will emit a value.

You might find the following article helpful in the future: Recipes for Combining Observables in RxSwift

let servers = Observable.combineLatest(serversViewModel.servers, serversViewModel.currentServer) { (servers, server) -> ([Server], IndexPath?) in
    let indexPath = server.flatMap { servers.firstIndex(of: $0) }
        .map { IndexPath(row: $0, section: 0) }
    return (servers, indexPath)
}

servers
    .map { $0.0 }
    .bind(to: serversTableView.rx.items(cellIdentifier: ServersTableViewCell.identifier, cellType: ServersTableViewCell.self)) { (row, element, cell) in
        cell.serverProxy.accept(element)
    }
    .disposed(by: disposeBag)

servers
    .map { $0.1 }
    .bind(onNext: { [serversTableView] indexPath in
        if let indexPath = indexPath {
            serversTableView.selectRow(at: indexPath, animated: true, scrollPosition: .top)
        }
        else {
            serversTableView.deselectAllItems(animated: false)
        }
    })
    .disposed(by: disposeBag)

Upvotes: 6

kerry
kerry

Reputation: 2582

There are several ways to combine observables in RxSwift. For your specific case, you will have to choose one that suits your needs best. Some of the operators are:

combineLatest zip merge etc.

Read this documentation to get more idea about what each one it does.

Upvotes: 0

Related Questions