Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get model from UICollectionView indexpath

I'm using RxSwift to bind a model array to a collection view

How do I get the model object from a given indexPath?

I'm doing the binding like this:

vm.bikeIssueCatagories()
        .drive(self.collectionView.rx.items(cellIdentifier: "BikeIssueCategoryCollectionViewCell", cellType: UICollectionViewCell.self)) { row, data, cell in
        }.disposed(by: disposeBag)

The core of my issue is, that I need to get both the model object and the cell that a user selects. Using collectionView.rx.modelSelected(T.self) only gives me the model og type T. And calling collectionView.rx.itemSelected only gives me the selected IndexPath

collectionView.rx.itemSelected.asDriver()
        .driveNext { [unowned self] indexPath in
            guard let model = try? collectionView.rx.model(at: indexPath) else { return }
            guard let cell = self.collectionView.cellForItem(at: indexPath) else { return }
        }.disposed(by: disposeBag)

But this gives me an error when trying to the the model at indexPath:

Type 'inout UICollectionView' does not conform to protocol 'ReactiveCompatible'

Just trying:

let indexPath = IndexPath.init()
self.collectionView.rx.model(at: indexPath)

also gives me an error:

Ambiguous reference to member 'model(at:)'

SO... How to get both the model object and the cell that a user selects?

like image 506
Wiingaard Avatar asked Oct 20 '25 04:10

Wiingaard


2 Answers

I could have done like RamwiseMatt proposed. Making a method on my ViewModel that takes the IndexPath and return the model. I did however end up using a zip:

let modelSelected = collectionView.rx.modelSelected(SelectableBikeIssueCategory.self).asObservable()

let cellSelected = collectionView.rx.itemSelected.asObservable()
            .map { [weak self] indexPath -> UICollectionViewCell in
                guard let cell = self?.collectionView.cellForItem(at: indexPath) else { fatalError("Expected cell at indexpath") }
                return cell
            }

Observable.zip(cellSelected, modelSelected)
            .map { [weak self] cell, category -> SomeThing in
                return SomeThing()
            }
like image 147
Wiingaard Avatar answered Oct 21 '25 18:10

Wiingaard


Your self-accepted solution is not optimal, because the modelSelected stream maps indexPath internally and needs to be used when there is no need to know about indexPath. In your case, it is better to use use itemSelected and convert to a tuple for example.

 collectionView.rx.itemSelected
    .map { [weak self] indexPath in
            guard
               let model = try? self?.collectionView.rx.model(at: indexPath) as YourModelName?,
               let cell = self?.collectionView.cellForItem(at: indexPath)  
            else {
                preconditionFailure("Describing of error")
            }


            return (cell, model)
        }
like image 45
headstream Avatar answered Oct 21 '25 20:10

headstream



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!