【问题标题】:RxDataSources tableView with multiple sections from one API sourceRxDataSources tableView 具有来自一个 API 源的多个部分
【发布时间】:2019-08-18 02:28:54
【问题描述】:

目前对于我们的 API 请求,我们使用 Rx。我们如何使用它的一个例子是:

let orderRxService = OrderRxService.listAsShop(shopId, status: .active)
    .repeatRequest(delay: 4)
    .observeOn(MainScheduler.instance)
    .subscribe( onNext: { [weak self] orders in
        self?.orders = orders
        self?.tableView.reloadData()
    })
    .disposed(by: disposeBag)

这将获取给定shopId 的所有订单,状态为.active。每次更新时,都会替换本地 orders 对象并重新加载 tableView。

这会重新加载我们想要避免的整个 tableView。我现在正在研究 RxDataSources,但无法真正弄清楚它的工作方式。

一个Order 对象有另一个属性currentStatus,它可以是3 个不同的值。 我们拥有的是一个包含 3 个不同部分的 tableView,每个部分显示 currentStatus 的所有订单。

这应该如何在 RxDataSources 中实现?理想情况下,将其绑定到我之前展示的服务 (OrderRxService.....subscribe()..)。

我现在需要设置 RxDataSources 类型是:

extension Order: IdentifiableType, Equatable {
    public typealias Identity = String

    public var identity: String {
        return String(id)
    }

    public static func == (lhs: Order, rhs: Order) -> Bool {
        return (lhs.timeCreated ?? 0) > (rhs.timeCreated ?? 0)
    }
}

struct OrdersSection {
    var header: String
    var orders: [Order]
}

extension OrdersSection: AnimatableSectionModelType {
    typealias Item = Order
    typealias Identity = String

    var identity: String {
        return header
    }

    var items: [Item] {
        set {
            orders = items
        }
        get {
            return orders
        }
    }

    init(original: OrdersSection, items: [Order]) {
        self = original
        self.items = items
    }
}

我试图让它发挥作用的是:

// I tried to make our local orders a Variable (I don't like this between-step and would like this to be just [Order]).
var orders: Variable<[Order]> = Variable([])


fun viewDidLoad() {
    super.viewDidLoad()

    // Then I set the local orders-variable's value to the new value coming from our Rx service.
    let orderRxDisposable: Disposable = OrderRxService.listAsShop(shopId, status: .active)
        .repeatRequest(delay: 4)
        .observeOn(MainScheduler.instance)
        .map { $0.items }.subscribe( onNext: { [weak self] orders in
            self?.orders.value = orders
        })

    // Here I setup the dataSource
    let dataSource = RxTableViewSectionedAnimatedDataSource<OrdersSection>(
        configureCell: { ds, tv, ip, item in
            let cell = tv.dequeueReusableCell(withIdentifier: "OrderCell", for: ip) as! OrderCell
            cell.addContent(item, tableView: tv, viewController: self, spotDelegate: self)
            return cell
        },

        titleForHeaderInSection: { ds, ip in
            return ds.sectionModels[ip].header
        }
    )

    // Here I set up the three different sections.
    self.orders.asObservable().observeOn(MainScheduler.instance)
        .map { o in
            o.filter { $0.currentStatus == .status_one }
        }
        .map { [OrdersSection(header: "Status one", orders: $0)] }
        .bind(to: self.tableView.rx.items(dataSource: dataSource))

    self.orders.asObservable().observeOn(MainScheduler.instance)
        .map { o in
            o.filter { $0.currentStatus == .status_two }
        }
        .map { [OrdersSection(header: "Status two", orders: $0)] }
        .bind(to: self.tableView.rx.items(dataSource: dataSource))

    self.orders.asObservable().observeOn(MainScheduler.instance)
        .map { o in
            o.filter { $0.currentStatus == .status_three }
        }
        .map { [OrdersSection(header: "Status three", orders: $0)] }
        .bind(to: self.tableView.rx.items(dataSource: dataSource))

}

可能有不同的方面可以改进。例如Variable&lt;[Order]&gt; 我想成为[Order]。 而不是使这个可观察的,可以完全跳过它并通过观察我们的 OrderRxService 创建三个不同的部分吗?

有没有可能是这样的:

OrderRxService.listAsshop(shopId, status: .active).observeOn(MainScheduler.instance)
    // First section
    .map { o in
        o.filter { $0.status == .status_one }
    }
    .map { [OrdersSection(header: "Status one", orders: $0)] }
    .bind(to: self.tableView.rx.items(dataSource: dataSource))
    // Second section
    .map { o in
        o.filter { $0.status == .status_two }
    }
    .map { [OrdersSection(header: "Status two", orders: $0)] }
    .bind(to: self.tableView.rx.items(dataSource: dataSource))
    // Etc...

感谢您的帮助!

【问题讨论】:

    标签: ios swift rx-swift rxdatasources


    【解决方案1】:

    您不需要映射->绑定->映射->绑定...您可以像这样在一个“映射”中简单地处理它:

    OrderRxService.listAsshop(shopId, status: .active).observeOn(MainScheduler.instance)
        .map { orders in
            let sections: [OrdersSection] = []
    
            sections.append(OrdersSection(header: "Status one", orders: orders.filter { $0.status == .status_one })
            
            sections.append(OrdersSection(header: "Status two", orders: orders.filter { $0.status == .status_two })
     
            sections.append(OrdersSection(header: "Status three", orders: orders.filter { $0.status == .status_three })
            
            return sections
        }
        .bind(to: self.tableView.rx.items(dataSource: dataSource))
        .disposed(by: disposeBag)
    

    另外,如果你经常使用 RxSwift/RxDataSources/etc 并且需要指导,加入 RxSwift Slack 频道是一个很好的资源: Invite to RxSwift Slack

    【讨论】:

      【解决方案2】:

      你可以像这样创建一个模型:

      enum SectionModel {
        case SectionOne(items: [SectionItem])
        case SectionTwo(items: [SectionItem])
        case SectionThree(items: [SectionItem])
      }
      
      enum SectionItem {
        case StatusOne()
        case StatusTwo()
        case StatusThree()
      }
      
      extension SectionModel: SectionModelType {
        typealias Item = SectionItem
      
        var items: [SectionItem] {
            switch self {
            case .SectionOne(items: let items):
                return items.map { $0 }
            case .SectionTwo(items: let items):
                return items.map { $0 }
            case.SectionThree(items: let items):
                return items.map { $0 }
            }
        }
      
        init(original: SectionModel, items: [Item]) {
            switch  original {
            case .SectionOne(items: _):
                self = .SectionOne(items: items)
            case .SectionTwo(items: _):
                self = .SectionTwo(items: items)
            case .SectionThree(items: _):
                self = .SectionThree(items: items)
            }
        }
      }
      

      并处理数据源中的不同项目

      dataSource = RxCollectionViewSectionedReloadDataSource<SectionModel>(configureCell: { (datasource, collectionView, indexPath, _) in
              switch datasource[indexPath] {
              case .StatusOne:
                  let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellOne, for: indexPath)!
                  // do stuff
                  return cell
              case .StatusTwo:
                  let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellTwo, for: indexPath)!
                  // do stuff
                  return cell
              case .StatusThree:
                  let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellThree, for: indexPath)!
                  // do stuff
                  return cell
              }
          })
      

      然后将您的 oders 映射到 SectionItemSectionModel 并将其绑定到数据源

      【讨论】:

      • 感谢您的详细回答!我觉得这是朝着正确方向迈出的一步。在我得到这个概念之前只有几个问题(顺便说一句,我有一个tableView,但我想这并没有太大变化)。我在哪里看到Order?我不知道[Order] 被过滤到3 个不同的位置。我看到有 3 种状态,但我无法将其与 Order.status 联系起来。看来SectionItem 应该改为Order 来解决我的问题?还是不正确?
      • 我想RxCollectionViewSectionedReloadDataSource&lt;DocumentSectionModel&gt; 可能是RxTableViewSectionedReloadDataSource&lt;SectionModel&gt;? :-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 2018-09-11
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多