RxSwift——TableView+Rx 数据源方法 items 分析

1,368 阅读2分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

前言

  _ = Observable
      .of(["1", "2", "3"])
      .bind(to: tableView.rx.items) { tb , ip, item in
      let cell = tb.dequeueReusableCell(withIdentifier: "cell")!
      cell.textLabel?.text = item
      return cell
      }
      .disposed(by: disposeBag)

使用 Sequence 数据序列 绑定 tableView.rxitems 方法可以快速展示一个 tableView

思考:items 方法是怎样实现实现的,items 方法 必须完成那些功能才能实现 tableView 的展示?

  1. 必须实现 UITableViewDataSource
  2. 必须能监听、获取 Sequence 数据序列并保存
  3. 必须 Sequence 改变能自动刷新 TableView

理解 bind(to: ) 方法, 展开语法糖

public func bind<R1, R2>(to binder: (Self) -> (R1) -> R2, curriedArgument: R1) -> R2
   _ = Observable
       .of(["1", "2", "3"])
       .bind(to: tableView.rx.items, curriedArgument: { tb , ip, item in
           let cell = tb.dequeueReusableCell(withIdentifier: "cell")!
           cell.textLabel?.text = item
           return cell
       })
       .disposed(by: disposeBag)

Xnip2021-08-11_11-53-41.png

理解 items( _ source: Source) 方法

Xnip2021-08-11_13-53-58.png

理解 items(dataSource: DataSource) 方法

Xnip2021-08-11_14-50-32.png

简化逻辑后的 items(dataSource: DataSource) 实现

  // 设置 TableView 的 UITableViewDataSource 实现 为 dataSource 对象
  let unregisterDelegate = RxTableViewDataSourceProxy.installForwardDelegate(dataSource, retainDelegate: true, onProxyForObject: self.base)
  
  // 订阅 source
  let reloadTableView = source.subscribe {[weak tableView = self.base] event in
      guard let tableView = tableView else {return}
      
      // dataSource: RxTableViewReactiveArrayDataSourceSequenceWrapper<[String]> 更新数据源 即 var itemModels: [Element]?
      // tableView.reloadData() 更新 TableView
      dataSource.tableView(tableView, observedEvent: event)
  }
  
  // 返回一个可销毁对象,在销毁时,同时销毁 unregisterDelegate 和 reloadTableView
  return Disposables.create {
      unregisterDelegate.dispose()
      reloadTableView.dispose()
  }

理解 UITableViewRxTableViewDataSourceProxyRxTableViewReactiveArrayDataSource 关系

Xnip2021-08-11_15-34-16.png

此关系中的代码片段摘要

获取 RxTableViewDataSourceProxy 对象(DelegateProxyType.swift/181行)

Xnip2021-08-11_16-13-16.png

设置 TableViewDataSourceDelegateProxyType.swift/285行)

Xnip2021-08-11_16-17-46.png

设置重定向对象 _setForwardToDelegate_RXDelegateProxy.m/95行)

Xnip2021-08-11_16-14-06.png

消息重定向 forwardInvocation_RXDelegateProxy.m/117行)

Xnip2021-08-11_16-14-13.png

理解 DelegateProxyFactory 如何创建 DelegateProxyType

Xnip2021-08-11_16-30-54.png

符合 DelegateProxyType协议的类创建唯一一个工厂,都保存在 _sharedFactories 字典中

Xnip2021-08-11_16-46-28.png

通过 _factories 字典存储 一个类生成 Proxy 对象的方法

Xnip2021-08-11_17-09-08.png

Xnip2021-08-11_17-10-21.png

在创建工厂对象时,添加创建 Proxy 对象的闭包。后面通过调用闭包创建 Proxy 对象

工厂实现新思路:

通过 字典 和 闭包 实现工厂方法

总结:

  • 使用 Rx 设置代理的底层实现

    //1. factory.createProxy(for:) 工厂方法创建 RxTableViewDataSourceProxy 对象A
    open class RxTableViewDataSourceProxy: DelegateProxy<UITableView, UITableViewDataSource>, DelegateProxyType , UITableViewDataSource;
    
    //2. 创建具体实现 UITableViewDataSource 的 _RxTableViewReactiveArrayDataSource 的对象B
    class _RxTableViewReactiveArrayDataSource: NSObject, UITableViewDataSource
    
    //3. 对象A 继承_RXDelegateProxy 通过 _setForwardToDelegate 保存 对象B
    -(void)_setForwardToDelegate:(id __nullable)forwardToDelegate retainDelegate:(BOOL)retainDelegate;
    
    //4. 对象A 继承_RXDelegateProxy 通过实现 forwardInvocation 方法将代理消息转发给B
    @interface _RXDelegateProxy : NSObject
    open class DelegateProxy<P: AnyObject, D>: _RXDelegateProxy
    
  • UITableView.rx 的 itmes 方法的实现

    1. 创建 RxTableViewReactiveArrayDataSourceSequenceWrapper 对象

      • var itemModels: [Element]? 保存数据源
      • let cellFactory: CellFactory 创建 UITableViewCell,并将闭包保留给 items 方法
      • tableView(**_** tableView: , observedElements:) 设置数据源,reloadData()
    2. 调用 subscribeProxyDataSource, 做3件事

      1. 使用 installForwardDelegate 方法

        • 使用工厂方法创建 RxTableViewDataSourceProxy 对象
        • 使用 setForwardToDelegate 方法设置 具体实现 UITableViewDataSource 的对象 为 RxTableViewReactiveArrayDataSourceSequenceWrapper 对象
        • 创建 Disposable 对象,在订阅销毁后释放资源
      2. 订阅数据源在接收到数据后调用 RxTableViewReactiveArrayDataSourceSequenceWrapper 对象的 tableView(**_** tableView: , observedElements:) 方法设置数据源,reloadData()

      3. 创建 Disposable 对象,在订阅销毁后释放资源