2

我正在使用 RXSwift 和 MVVM 为 iPad 制作应用程序。

我有一个带有 UICollectionView 和 ViewModel 的 UIViewController,它充当数据源和 collectionView 的委托。

收集单元格的部分功能是当点击按钮以显示弹出框时。现在使用 iOS 9 中更新的弹出框功能(可能更早),您需要在视图控制器中正常显示视图,并修改 popoverPresentationController。

现在,据我所知,您无法从 UICollectionViewCell 呈现 UIViewController。说得通。

但我认为这样做的唯一方法是拥有一个指向 ViewController 的委托。

查看类图(附加),viewModel 必须在单元格出列时设置委托。要做到这一点,ViewModel 必须知道要设置什么 ViewController 作为委托,我相当肯定这与 viewModel 的观点相悖。根据 MVVM(对于 iOS),视图模型不应该知道视图控制器。视图控制器可以知道视图模型。

所以我的问题是在 MVVM 之后执行此操作的最佳方法是什么?如果它需要将 dataSource/Delegate 移动到不同的类,我完全赞成。

UML 图

4

1 回答 1

1

我认为视图模型根本不应该知道被点击的按钮。处理触摸事件属于视图层,以及呈现弹出框。

这也表明您的视图模型不应该是UICollectionViewDataSource. 所以它与RootCollectionViewCell,这是一个视图。不幸的是,这种耦合很难避免,因为 AppleUICollectionViewDataSource就是这样设计的。您可以提取一个单独的类作为数据源,也可以将数据源方法留在视图控制器中(在 iOS 上属于 MVVM 中的视图层)。

使用 RxCocoa,你甚至可以完全避免实现UICollectionViewDataSource方法。看看UICollectionView+Rx扩展。RxSwift 存储库中还有一个示例(包含集合视图的表格视图单元格)。

要将按钮点击传递给视图控制器,您可以使用rx_tapObservable 并将其公开在单元格的界面中。然后您可以订阅Observable视图控制器(或单独的数据源类)中的结果:

//in the cell class
var buttonTapped : ControlEvent<Void> {
    return button.rx_tap
}

//in the data source 
cell.buttonTapped.subscribeNext {
  //show the popover
}.addDisposableTo(cell.disposeBag)

this answer中所述,您应该避免在重复使用单元格时多次订阅同一个 Observable。这就是cell.disposeBag上面代码中使用的原因。disposeBag您还应该在其prepareForReuse方法中重新创建单元格:

class RootCollectionViewCell: UICollectionViewCell {

    var disposeBagCell:DisposeBag = DisposeBag()

    ...

    override func prepareForReuse() {
        disposeBagCell = DisposeBag()
    }

}
于 2016-04-05T08:13:05.120 回答