使用 RxSwift 的 UICollectionView 数据绑定 - iOS

Posted

技术标签:

【中文标题】使用 RxSwift 的 UICollectionView 数据绑定 - iOS【英文标题】:UICollectionView databinding using RxSwift - iOS 【发布时间】:2020-01-10 15:12:50 【问题描述】:

我有一个填充了数据模型的集合视图。当用户点击 collectionview 单元格时,我正在尝试更新嵌套模型的 bool 属性。反过来,collectionview 应该重新加载,并且 cell 应该更新为 bool 属性。但是模型中的属性变化并没有更新collectionview。

//型号

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)

//视图模型

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】:

您必须调用 items.accept(_:) 才能将一个新数组从您的 BehaviorRelay 中推出。为此,您必须构建一个新数组。此外,BehaviorRelays(任何中继或主题)不应该是vars;他们应该总是lets。

另外,请记住,您实际上不能修改继电器中的数组。相反,您将其替换为一个新数组。

这应该可行:

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

【讨论】:

keep in mind that you can't actually modify the array in the relay - 是的。我认为由于 behaviorRelay 是变化的传播,我们不能替换已经发出的值。

以上是关于使用 RxSwift 的 UICollectionView 数据绑定 - iOS的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UICollection 补充视图中使用 UIButton?

如何使用装饰器视图在 uicollection 视图中实现所需的设计

使用 UICollection 中的部分访问数据库

UICollection 在使用 Swift 3 显示图像时非常慢

在 UITableviewCell 中使用 UICollection 视图时未调用 UICollectionView 委托方法“didSelectItemAtIndexPath”

UICollection 的镜像滚动