Devesh Laungani
Devesh Laungani

Reputation: 129

MVVM RxSwift way to send data from main view to detail view controller?

I have a view model that has an element that returns an observable array after calling an API.

I then find that result to a table view to display it. The problem I am having is how to call the detail view controller on the specific cell that is clicked. I bound the results with:

 let queryResults = eventsViewModel.mainTableItems

       queryResults
            .bind(to: collectionView.rx.items) { collectionView, row, item in

                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: IndexPath(row: row, section: 0)) as! EventCell
                cell.heroID = "heroCellID"
                cell.restaurantNameLabel.text = item.name
                cell.restaurantDetailLabel.text = item.location
                cell.timeLabel.text = item.date
                cell.restaurantImageView.kf.setImage(with: URL(string: item.image))

                return cell
        }
        .addDisposableTo(disposeBag)

I have no way to access the specific element in this observable array that was clicked. It says an Observable array cannot have subscript.

This is the code that says that:

 vc.festival = queryResults.value[indexPath.row]

I am still new to RxSwift and I am struggling to understand this.

Upvotes: 3

Views: 2594

Answers (2)

user6354073
user6354073

Reputation:

Depending on the complexity of your app, as Daniel suggested- creating a high level coordinator object may be the best option. One simple option is to create a property in eventsViewModel and assign a value to it from within tableView.rx.itemSelected. Then when you prepare for segue, you can retrieve object from eventsViewModel, like so:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if segue.identifier == "identifier" {
        let detailVC = segue.destination as! DetailViewController
        if let selectedItem = eventsViewModel.item {
            detailVC.viewModel = DetailViewModel(item: selectedItem)
        }
    }
}

probably not the best solution but it does work as intended.

Upvotes: 0

Daniel T.
Daniel T.

Reputation: 33967

This really is the million dollar question, and something that has a lot of different answers and none are really simple, even without using RxSwift. The short answer is, it depends on how your app is architected.

First thing, if you haven't already realized, is that you find out which item was selected with tableView.rx.itemSelected.

IMHO, view controllers should be independent of each other so the one thing you don't want to do is create or segue to the detail view controller from this one. There should be some sort of coordinator object that subscribes to itemSelected and is in charge of deciding where to go from there.

Here are some good articles to get you on the right track:

http://rasic.info/a-different-take-on-mvvm-with-swift/

In this article, Mr. Rasic talks about a class that he calls the Scene which is in charge of creating the view controller and its view mode, attaching them and then deciding where to go from there.

http://khanlou.com/2015/01/the-coordinator/

In this article, Mr. Khanlou talks about a class that he calls the Coordinator. He doesn't use Rx, instead he uses delegates, but it's pretty easy to see how it would relate.

https://talk.objc.io/episodes/S01E05-connecting-view-controllers

This is a video where the objc.io team creates an App class that takes care of view controller navigation. They use closures here instead of Rx, but again the correspondence should be obvious.

Upvotes: 2

Related Questions