如何将“Observable”转换为“ControlEvent”

Yuc*_*ong 1 ios swift rx-swift

我们有一个视图控制器MainCollectionView,其中包含一个带有多个单元格的集合视图FooCell。每个内部FooCell都有一个集合视图和一个单元格列表BarCell

BarCell如何在to中传播按钮点击事件MainCollectionView

这就是我们所拥有的:

class FooCell: ... {

    private let barCellButtonTappedSubject: PublishSubject<Void> = PublishSubject<Void>()
    var barCellButtonTappedObservable: Observable<Void> {
        return barCellButtonTappedSubject.asObserver()
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeue(...)

        if let cell = cell as BarCell {
            cell.button.rx.tap.bind { [weak self] in
                self?.barCellButtonTappedSubject.onNext(())
            }.disposed(by: cell.rx.reusableDisposeBag)
        }

        return cell
    }
}

class MainCollectionView: ... {

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeue(...)

        if let cell = cell as FooCell {
            cell.barCellButtonTappedObservable.subscribe { [weak self] in
                // Do other stuff when the button inside bar cell is tapped.
            }.disposed(by: cell.rx.reusableDisposeBag)
        }

        return cell
    }
}
Run Code Online (Sandbox Code Playgroud)

这一直有效,直到我读到ControlEvent

  • 它永远不会失败
  • 它不会发送任何订阅的初始值
  • 它将完成控制被释放的序列
  • 它永远不会出错
  • 它在 MainScheduler.instance 上传递事件

看起来它更适合用ControlEventFooCell

private let barCellButtonTappedSubject: PublishSubject<Void> = PublishSubject<Void>()
var barCellButtonTappedObservable: Observable<Void> {
    return barCellButtonTappedSubject.asObserver()
}
Run Code Online (Sandbox Code Playgroud)

barCellButtonTappedObservable将其转换为 a 的正确方法是什么ControlEvent?或者是否有其他更好的想法将ControlEvent嵌套单元格中的 传播到外部视图控制器?

San*_*ari 5

我个人更喜欢使用RxAction这种东西,但因为你已经PublishSubject<Void>在你的单元格中声明了 a,这就是你如何将主题转换为ControlEvent

controlEvent = ControlEvent<Void>(events: barCellButtonTappedSubject.asObservable())
Run Code Online (Sandbox Code Playgroud)

尽可能直接!但如果这就是你想做的,你甚至不需要barCellButtonTappedSubject

controlEvent = ControlEvent<Void>(events: cell.button.rx.tap)
Run Code Online (Sandbox Code Playgroud)

事实上,你甚至不需要声明一个控制事件:)因为cell.button.rx.tap它本身就是一个控制事件:)所以如果你在你的单元格中将你的按钮声明为公共属性,你可以直接在你的tableView控制器中访问它的点击控制事件

但就我个人而言,我会使用RxAction而不是声明publishSubjectcontrolEventFooCell可以要求您采取行动TableViewController

class FooCell: ... {
   var cellTapAction : CocoaAction! = nil

   func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeue(...)

        if let cell = cell as BarCell {
            cell.button.rx.action = cellTapAction
        }

        return cell
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,您的 TableViewController/CollectionViewController 可以将操作传递为

class MainCollectionView: ... {

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeue(...)

        if var cell = cell as FooCell {
            cell.cellTapAction = CocoaAction { _ -> Observable<Void> in
               debugPrint("button in cell tapped")
               return Observable.just(())
           }
        }

        return cell
    }
}
Run Code Online (Sandbox Code Playgroud)

您唯一需要处理的是,如果 cellctionView 嵌入在内部,因为在嵌入的 collectionView之后FooCell传递,甚至在将操作传递给它之前可能会加载,因此您必须调整逻辑以在操作传递给或任何其他之后重新加载嵌入的集合视图解决方法将解决这个问题:)actiondeQueReusableCellFooCell

希望它有帮助:) 我相信使用Action可以使代码更清晰且易于理解。