ios - 具有 RxSwift/RxDataSources 的表格 View 单元格中的高性能多个水平 Collection View

标签 ios swift rx-swift

您可以在大多数应用程序中找到一个著名的布局,即在表格 View 单元格中有几个水平列表,每个列表都从服务器获取数据。可以在 Airbnb 上找到。下面的例子:
每个列表都有一个加载 View 和一个空状态,以在出现问题时显示。
每个列表仅在第一次创建时触发网络请求,因此当通过滚动表格 View 再次显示时,它不应该再次发出网络请求来获取数据。
我尝试了几种方法,但还不满意。当有多个collectionview时,其中一些会遇到内存泄漏和性能问题。目前,我在 View Controller 中执行网络请求,该 Controller 包含 TableView 并将数据传递给每个单元格。
任何人都可以分享他们如何做到这一点的方法吗?赞赏!
例子:
enter image description here

最佳答案

这是一个巨大的问题,有很多不同的可能答案。我最近通过使用自定义表格 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>()
}
每个表格 View 单元都需要自己的 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提取它的特定状态。

关于ios - 具有 RxSwift/RxDataSources 的表格 View 单元格中的高性能多个水平 Collection View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63820054/

相关文章:

swift - 为什么在 retryWhen 计时器结束时使用 take(1)?

rx-swift - BehaviourRelay RxSwift 的私有(private)接受

iphone - 来自相机的 AVCaptureSession CVImageBufferRef 上的图层 OpenGL 内容

ios - 尝试在演示过程中显示 UIViewController!-警告

json - 针对 AnyObject JSON 错误的 Swift 2 到 3 迁移

ios - Twitter Api 如何将 unicode 转换为字符串?

ios - 由于日期选择器位于 View Controller 的顶部栏中,因此如何使日期选择器出现在按钮单击时

ios - 在 SpriteKit 中使用 AspectFit 显示边框外的内容

ios - 从我的 iPhone 或 Blackberry 访问本地托管的 Web 服务

ios - 使用 RxSwift 和 Parse-Server 进行轮询