ios - 具有 RxSwift/RxDataSources 的表格视图单元格中的高性能多个水平集合视图
问题描述
您可以在大多数应用程序中找到一个著名的布局,即在表格视图单元格中有几个水平列表,每个列表都从服务器获取数据。可以在 Airbnb 上找到。下面的例子:
每个列表都有一个加载视图和一个空状态,以在出现问题时显示。
每个列表仅在第一次创建时触发网络请求,因此当通过滚动表格视图再次显示时,它不应该再次发出网络请求来获取数据。
我尝试了几种方法,但还不满意。当有多个collectionview时,其中一些会遇到内存泄漏和性能问题。目前,我在 View 控制器中执行网络请求,该控制器包含表视图并将数据传递给每个单元格。
任何人都可以分享他们如何做到这一点的方法吗?赞赏!例子:
解决方案
这是一个巨大的问题,有很多不同的可能答案。我最近通过使用自定义表格视图数据源解决了这个问题,该数据源报告第一次(并且仅是第一次)项目由单元格显示。我用它来触发单个内部网络请求何时发生。它使用.distinct()
在 RxSwiftExt 中实现的运算符...
final class CellReportingDataSource<Element>: NSObject, UITableViewDataSource, RxTableViewDataSourceType where Element: Hashable {
let cellCreated: Observable<Element>
init(createCell: @escaping (UITableView, IndexPath, Element) -> UITableViewCell) {
self.createCell = createCell
cellCreated = _cellCreated.distinct()
super.init()
}
deinit {
_cellCreated.onCompleted()
}
func tableView(_ tableView: UITableView, observedEvent: Event<[Element]>) {
if case let .next(sections) = observedEvent {
self.items = sections
tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = items[indexPath.row]
let cell = createCell(tableView, indexPath, item)
_cellCreated.onNext(item)
return cell
}
private var items: [Element] = []
private let createCell: (UITableView, IndexPath, Element) -> UITableViewCell
private let _cellCreated = PublishSubject<Element>()
}
每个表格视图单元都需要自己的 Observable,每次订阅它时都会发出网络调用的结果。我通过使用.scan(into:accumulator:)
. 一个例子可能是这样的:
dataSource.cellCreated
.map { ($0, /* logic to convert a table view item into network call parameters */) }
.flatMap {
Observable.zip(
Observable.just($0.0),
networkCall($0.1)
.map { Result.success($0) }
.catchError { Result.failure($0) }
)
}
.scan(into: [TableViewItem: Result<NetworkResponse, Error>]()) { current, next in
current[next.0] = next.1
}
.share(replay: 1)
每个单元格都可以订阅上述内容并用于compactMap
提取它的特定状态。
推荐阅读
- nuxt.js - 如何在 nuxt.config.js 中使用 CopyWebpackPlugin?
- java - 如何在Java中对键上的地图列表进行排序?
- abap - 如何在 SAP ABAP 类中知道当前浏览器的 URL
- mysql - Mysql-Workbench 表浏览器窗格丢失
- python-2.7 - 从其他目录调用 python 脚本函数
- java - 如何将mongodb视图与pageable和querydsl结合起来?
- sql - SQL 将行转换为列并填充值
- java - setOnClickListener Android Studio(制作计数器)
- javascript - 通过代理的 Google Places API 超时
- cypress - 比较赛普拉斯中的动态文本