Get model from UICollectionView indexpath

余生颓废 提交于 2020-08-08 05:34:06

问题


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?


回答1:


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()
            }



回答2:


Your ViewModel defines a method bikeIssueCatagories(), which is what your UIViewController binds the UICollectionView to. To get your model at the correct position, you can use the itemSelected property you mentioned, which gives you an Observable<IndexPath>, which you should feed into your ViewModel. There, you can use the IndexPath's item property to determine which model from your data array (given in bikeIssueCatagories()) is the one you are looking for. The modelSelected property makes this easier for you since it already knows the datasource, so all you have to provide is the type of your Model (replace T.self with YourModelName.self.)

I'm not sure why you want a reference to your cell as well, but if you must, you can just use cellForItem(at:) on your UICollectionView (feeding it the IndexPath you obtained via itemSelected.)




回答3:


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)
        }


来源:https://stackoverflow.com/questions/46811630/get-model-from-uicollectionview-indexpath

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!