Estoy usando RxSwift para vincular una matriz de modelo a una vista de colección

¿Cómo obtengo el objeto modelo de un indexPath dado?

Estoy haciendo el enlace así:

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

El núcleo de mi problema es que necesito obtener tanto el objeto modelo como la celda que selecciona un usuario. Usar collectionView.rx.modelSelected(T.self) solo me da el modelo og tipo T. Y llamar a collectionView.rx.itemSelected solo me da el IndexPath seleccionado

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)

Pero esto me da un error al intentar el modelo en indexPath:

El tipo 'inout UICollectionView' no se ajusta al protocolo 'ReactiveCompatible'

Simplemente intentandolo:

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

También me da un error:

Referencia ambigua al miembro 'modelo (en :)'

SO ... ¿Cómo obtener tanto el objeto modelo como la celda que selecciona un usuario?

2
Wiingaard 18 oct. 2017 a las 16:41

3 respuestas

La mejor respuesta

Podría haber hecho lo que RamwiseMatt propuso. Haciendo un método en mi ViewModel que toma IndexPath y devuelve el modelo. Sin embargo, terminé usando un 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()
            }
5
Wiingaard 23 oct. 2017 a las 15:05

Su ViewModel define un método bikeIssueCatagories(), que es a lo que su UIViewController une el UICollectionView. Para obtener su modelo en la posición correcta, puede usar la propiedad itemSelected que mencionó, que le da un Observable<IndexPath>, que debe alimentar a su ViewModel. Allí, puede usar la propiedad item de IndexPath para determinar qué modelo de su matriz de datos (dado en bikeIssueCatagories()) es el que está buscando. La propiedad modelSelected lo hace más fácil ya que ya conoce la fuente de datos, por lo que todo lo que tiene que proporcionar es el tipo de su Modelo (reemplace T.self con YourModelName.self).

No estoy seguro de por qué quiere una referencia a su celda también, pero si debe hacerlo, puede usar cellForItem(at:) en su UICollectionView (alimentándolo con el IndexPath que obtuvo a través de itemSelected .)

1
RamwiseMatt 22 oct. 2017 a las 22:55

Su solución autoaceptada no es óptima, porque la secuencia modelSelected asigna indexPath internamente y debe usarse cuando no es necesario saber sobre indexPath. En su caso, es mejor usar use itemSelected y convertir a una tupla, por ejemplo.

 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)
        }
0
headstream 30 mar. 2020 a las 08:16