如何从 BehaviorRelay observable 更新 tableView?

Posted

技术标签:

【中文标题】如何从 BehaviorRelay observable 更新 tableView?【英文标题】:How can I update tableView from BehaviorRelay observable? 【发布时间】:2021-04-25 20:27:28 【问题描述】:

我正在尝试使用油门在表格视图中进行搜索。

这里我在 ViewModel 中有 BehaviorRelay

var countryCodes: BehaviorRelay<[CountryDialElement]> = BehaviorRelay<[CountryDialElement]>(value:[])

这里我有输入文本的 BehaviorRelay

var searchText: BehaviorRelay<String> = BehaviorRelay<String>(value: "")

这里我有与 View Model 中的 Observable 绑定的 Table View

self.viewModel.params.countryCodes.bind(to: tableView.rx.items(cellIdentifier: "CountryDialTableViewCell"))  index, model, cell in
      let countryCell = cell as! CountryDialTableViewCell
      countryCell.configure(model)
    .disposed(by: disposeBag)

这里我将 Rx 绑定到 ViewController 中的 UISearchBar

searchBar
      .rx
      .text
      .orEmpty
      .debounce(.milliseconds(300), scheduler: MainScheduler.instance)
      .distinctUntilChanged()
      .subscribe  [weak self] query in
        guard
          let query = query.element else  return 
        self?.viewModel.params.searchText.accept(query)
      
      .disposed(by: disposeBag)

然后在 ViewModel 中,我尝试过滤数据并将过滤后的数据推送到 dataSource,以更新 tableView。

Observable.combineLatest(params.countryCodes, params.searchText)  items, query in
      return items.filter( item in
        item.name.lowercased().contains(query.lowercased()) || item.dialCode.lowercased().contains(query.lowercased())
      )
    .subscribe(onNext:  resultArray in
      self.params.countryCodes.accept(resultArray)
    )
    .disposed(by: disposeBag)

但是我遇到了这种类型的错误

Reentrancy anomaly was detected.
This behavior breaks the grammar because there is overlapping between sequence events.
The observable sequence is trying to send an event before sending the previous event has finished.
Interpretation: This could mean that there is some kind of unexpected cyclic dependency in your code, or that the system is not behaving in an expected way.

我正在努力实现:

    带有可观察数组的绑定表视图 在搜索栏中输入文字 过滤可观察对象,数组 更新 observable,重新加载 tableView。

【问题讨论】:

【参考方案1】:

我注意到的第一件事...您有两个 BehaviorRelay 定义为 var。您应该始终使用let 定义它们。

您没有发布足够的代码来演示该错误,但正如错误消息中向您解释的那样,根本问题是您正在破坏 observable 语法,因为您在推送过程中通过 Observable 推送数据数据。如果允许,它会形成一个无限递归调用,会溢出堆栈。

在当前事件完成发送之前不要发送事件。如果你不使用这么多 Relay 会很有帮助...

你没有说数组中的项目来自哪里,这也很难帮助......

考虑这样的事情:

Observable.combineLatest(
    searchBar.rx.text.orEmpty
        .debounce(.milliseconds(300), scheduler: MainScheduler.instance)
        .distinctUntilChanged()
        .startWith(""),
    sourceOfItems(),
    resultSelector:  searchTerm, items in
        items.filter  $0.code.contains(searchTerm) 
    
)
.bind(to: tableView.rx.items(cellIdentifier: "CountryDialTableViewCell"))  index, model, cell in
    let countryCell = cell as! CountryDialTableViewCell
    countryCell.configure(model)

.disposed(by: disposeBag)

【讨论】:

谢谢你,丹尼尔。这对我帮助很大。感谢您的建议,在您的 sn-p 的启发下进行了一些重构之后,我的代码现在可以工作了。实际上,数据来自本地 JSON 文件。

以上是关于如何从 BehaviorRelay observable 更新 tableView?的主要内容,如果未能解决你的问题,请参考以下文章

在 RxCocoa/RxSwift 中,如何观察 BehaviorRelay<[object]> 数组大小发生变化

使用 Observable 绑定 BehaviorRelay - RxSwift

RxSwift : BehaviorRelay 代替变量使用

BehaviorRelay RxSwift 的私有接受

在 RxSwift 中修改 behaviorRelay 数组内的属性

RxSwift BehaviorRelay auto isDisposed