UICollectionView привязка данных с использованием RxSwift - iOS - PullRequest
1 голос
/ 10 января 2020

У меня есть представление коллекции, заполненное моделями данных. Я пытаюсь обновить свойство bool вложенной модели, когда пользователь нажимает на ячейку collectionview. В свою очередь, коллекция должна перезагрузиться, а ячейка должна быть обновлена ​​относительно свойства bool. Но изменение свойства в модели не обновляет представление коллекции.

// Модель

struct MultiSelectionQuestionModel {
  var header: String
  var items: [Item]
}

extension MultiSelectionQuestionModel: SectionModelType {
  typealias Item = MultiSelectionAnswerModel

   init(original: MultiSelectionQuestionModel, items: [Item]) {
        self = original
        self.items = items
  }
}

struct MultiSelectionAnswerModel {
    var text: String
    var isSelected: Bool = false //property to be updated
    var cellType: CellType = .CustomType
}

// Методы CollectionView

func populateCells() {
     let dataSource = RxCollectionViewSectionedReloadDataSource
                    <MultiSelectionQuestionModel>(
                configureCell: { (_, collectionView, indexPath, item) in
                    guard let cell = collectionView
                        .dequeueReusableCell(withReuseIdentifier: item.cellType.rawValue, for: indexPath) as? MultiSelectionBaseCell else {
                        return MultiSelectionBaseCell()
                    }
                    cell.configure(item: item)
                    return cell
                })

    //handle collectionview cell tap

    collectionView.rx.itemSelected.asObservable().map { (indexPath) -> Result in
        //This method is called to update `isSelected` property. Once `isSelected` is updated. I am expecting the collectionview to reload and update the cell.
        self.viewModel.toggleItemSelected(indexPath: indexPath)
    }
    collectionView.rx.setDelegate(self).disposed(by: disposeBag)

    viewModel.items
            .bind(to: collectionView.rx.items(dataSource: dataSource))
                  .disposed(by: disposeBag)
}

// ViewModel

struct MultiSelectionCollectionViewModel {
    var items: BehaviorRelay<[MultiSelectionQuestionModel]> = BehaviorRelay(value: [])
    var delegate:
    init(questions: BehaviorRelay<[MultiSelectionQuestionModel]>) {
        self.items = questions
    }

    //This method is called to update `isSelected` property. Once `isSelected` is updated. I am expecting the collectionview to reload and update the cell.
    func toggleItemSelected(indexPath: IndexPath) {
        let item = self.items.value[indexPath.section]
        if let options = item.items as? [MultiSelectionAnswerModel] {
            var optionItem = options[indexPath.row]
            optionItem.isSelected = true // Collectionview reload Not working. 
        } 
    }
}

Я только начал изучать RxSwift. Любая помощь приветствуется. Спасибо

1 Ответ

1 голос
/ 10 января 2020

Вы должны вызвать items.accept(_:) для pu sh нового массива из вашего BehaviorRelay. Чтобы сделать это, вы должны построить новый массив. Кроме того, BehaviorRelays (любые реле или темы) никогда не должно быть var с; они всегда должны быть let с.

Кроме того, имейте в виду, что вы не можете модифицировать массив в реле. Вместо этого вы заменяете новым массивом.

Это должно работать:

struct MultiSelectionCollectionViewModel {
    let items: BehaviorRelay<[MultiSelectionQuestionModel]>

    init(questions: BehaviorRelay<[MultiSelectionQuestionModel]>) {
        self.items = questions
    }

    //This method is called to update `isSelected` property. Once `isSelected` is updated. I am expecting the collectionview to reload and update the cell.
    func toggleItemSelected(indexPath: IndexPath) {
        var multiSelectionQuestionModel = items.value // makes a copy of the array contained in `items`.
        var item = multiSelectionQuestionModel[indexPath.section].items[indexPath.row] // makes a copy of the item to be modified
        item.isSelected = true // modifies the item copy
        multiSelectionQuestionModel[indexPath.section].items[indexPath.row] = item // modifies the copy of items by replacing the old item with the new one
        items.accept(multiSelectionQuestionModel) // tells BehaviorRelay to update with the new array of items (it will emit the new array to all subscribers.)
    }
}

protocol SectionModelType { }

enum CellType {
    case CustomType
}

struct MultiSelectionQuestionModel {
    var header: String
    var items: [Item]
}

extension MultiSelectionQuestionModel: SectionModelType {
    typealias Item = MultiSelectionAnswerModel

    init(original: MultiSelectionQuestionModel, items: [Item]) {
        self = original
        self.items = items
    }
}

struct MultiSelectionAnswerModel {
    var text: String
    var isSelected: Bool = false //property to be updated
    var cellType: CellType = .CustomType
}
...