Ios 具有RxSwift/RxDataSources的表视图单元格中的多个高性能水平集合视图

Ios 具有RxSwift/RxDataSources的表视图单元格中的多个高性能水平集合视图,ios,swift,rx-swift,Ios,Swift,Rx Swift,在大多数应用程序中,一个著名的布局是在表视图单元格中有几个水平列表,每个列表从服务器获取数据。可在Airbnb中找到。示例如下: 每个列表都有一个加载视图和一个空状态,用于在出现问题时显示 每个列表仅在第一次创建时触发网络请求,因此当通过滚动表视图再次显示时,它不应发出另一个获取数据的网络请求 我尝试了几种方法,但还不满意。其中一些在具有多个collectionview时会遇到内存泄漏和性能问题。目前,我在保存表视图的视图控制器中执行网络请求,并将数据传递给每个单元格 任何人都可以分享他们如何做

在大多数应用程序中,一个著名的布局是在表视图单元格中有几个水平列表,每个列表从服务器获取数据。可在Airbnb中找到。示例如下:

每个列表都有一个加载视图和一个空状态,用于在出现问题时显示

每个列表仅在第一次创建时触发网络请求,因此当通过滚动表视图再次显示时,它不应发出另一个获取数据的网络请求

我尝试了几种方法,但还不满意。其中一些在具有多个collectionview时会遇到内存泄漏和性能问题。目前,我在保存表视图的视图控制器中执行网络请求,并将数据传递给每个单元格

任何人都可以分享他们如何做到这一点的方法吗?谢谢! 例如:


这是一个巨大的问题,可能有很多不同的答案。我最近通过使用一个自定义表视图数据源解决了这个问题,该数据源报告单元格第一次(并且仅第一次)显示项。我用它来触发单独的内部网络请求。它使用在RxSwiftExt中实现的
.distinct()
运算符

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>()
}

每个单元格都可以订阅上述内容,并使用
compactMap
提取其特定的状态。

您可以尝试脱机缓存机制。这样,您可以在滚动时显示缓存的数据,也可以在后台执行网络调用并与脱机数据同步。如果视图仍然可用,请更新视图。
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)