Какой будет правильная архитектура MVVM для UICollectionViewController
Я делаю приложение для iPad, используя RXSwift и MVVM.
У меня есть UIViewController с UICollectionView и ViewModel, который действует как источник данных и делегат для collectionView.
Часть функциональности ячеек коллекции заключается в том, что при нажатии кнопки появляется поповер. Теперь с более новой функциональностью popover в iOS 9 (возможно, ранее) вам нужно нормально представить представление в контроллере представления и изменить popoverPresentationController.
Теперь, насколько мне известно, вы не можете представить UIViewController из UICollectionViewCell. Имеет смысл.
Но единственный способ, которым я думал сделать это, был бы иметь делегата, который указывает на ViewController.
Глядя на диаграмму классов (прилагается), viewModel должен был бы установить делегат при отключении ячейки. Чтобы сделать это, ViewModel должен знать, какой ViewController установить в качестве делегата, который, я уверен, идет вразрез с точкой зрения модели. Согласно MVVM (для iOS) модель представления не должна знать о контроллере представления. Контроллер вида может знать о модели вида.
И поэтому мой вопрос, что было бы лучшим способом сделать это после MVVM? Если это требует перемещения dataSource/Delegate в другой класс, я все для этого.
1 ответ
Я думаю, что модель представления не должна знать о нажатии кнопки вообще. Обработка сенсорных событий принадлежит слою представления, а также представляет всплывающее окно.
Это также указывает на то, что ваша модель представления не должна быть UICollectionViewDataSource
, Так что в сочетании с RootCollectionViewCell
, который является представлением. К сожалению, эту связь трудно избежать, потому что Apple разработала UICollectionViewDataSource
сюда. Вы можете либо извлечь отдельный класс в качестве источника данных, либо оставить методы источника данных в контроллере представления (который принадлежит слою представления в MVVM на iOS).
Используя RxCocoa, вы даже можете избежать реализации UICollectionViewDataSource
методы вообще. Взгляни на UICollectionView+Rx
расширения. Есть также пример в репозитории RxSwift (ячейка табличного представления, содержащая представление коллекции).
Для передачи нажатий кнопки на контроллер представления вы можете использовать rx_tap
Наблюдаем и выставляем его в интерфейсе ячейки. Тогда вы можете подписаться на полученный 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)
Как описано в этом ответе, вам следует избегать многократной подписки на один и тот же Observable при повторном использовании ячейки. Вот почему cell.disposeBag
используется в коде выше. Вы также должны воссоздать ячейки disposeBag
в его prepareForReuse
метод:
class RootCollectionViewCell: UICollectionViewCell {
var disposeBagCell:DisposeBag = DisposeBag()
...
override func prepareForReuse() {
disposeBagCell = DisposeBag()
}
}