RxSwift:使用 rx_refreshing 进行 uirefreshcontrol

Posted

技术标签:

【中文标题】RxSwift:使用 rx_refreshing 进行 uirefreshcontrol【英文标题】:RxSwift: using rx_refreshing for uirefreshcontrol 【发布时间】:2016-07-25 23:22:24 【问题描述】:

我正在使用UIRefreshControl + Variable 绑定重新加载数据。

它正在工作,但是,我觉得以下内容不对:

1) 我知道在 RXCocoa 扩展中有一个 rx_refreshing 变量,但我无法让它在这种情况下工作。

2) 我绑定了两次答案(这是数组的Variable)。一次是在我加载视图控制器时,另一次是在 UIRefreshControl 刷新时。

3) 我检查UIRefreshControl 是否令人耳目一新的部分看起来真的很尴尬。感觉好像违背了使用响应式的目的?

...

let answers: Variable<[Answer]> = Variable([])

override func viewDidLoad()        
  loadAnswers()
     .shareReplay(1)
     .bindTo(answers)
     .addDisposableTo(self.disposeBag)
  setupRx()


func loadAnswers() -> Observable<[Answer]> 
  return Network.rxArrayRequest(Spark.Answers)
  

func setupRx() 
  rc.rx_controlEvent(.ValueChanged)
    .map  _ in !self.rc.refreshing 
    .filter  $0 == false 
    .flatMapLatest  [unowned self] _ in
      return self.loadAnswers()
    
    .bindTo(answers)
    .addDisposableTo(self.disposeBag)

  rc.rx_controlEvent(.ValueChanged)
    .map  _ in self.rc.refreshing 
    .filter  $0 == true 
    .subscribeNext  [unowned self] _ in
      self.rc.endRefreshing()
    
    .addDisposableTo(self.disposeBag)


...

【问题讨论】:

【参考方案1】:

首先,它没有真正起作用。它只是似乎在工作。在您的代码中,您实际上并没有在调用rc.endRefreshing() 之前等待网络请求完成。相反,您只是进行网络调用,然后立即调用endRefreshing()

// `rc.rx_controlEvent(.ValueChanged)` only gets called once,
// when the user pulls down.

rc.rx_controlEvent(.ValueChanged)       // user pulled down to refresh
  .map  _ in !self.rc.refreshing      // !true -> false 
  .filter  $0 == false                // false == false
  .flatMapLatest  [unowned self] _ in
    return self.loadAnswers()           // request answers
  
  .bindTo(answers)
  .addDisposableTo(self.disposeBag)

rc.rx_controlEvent(.ValueChanged)       // user pulled down to refresh
  .map  _ in self.rc.refreshing       // true -> true
  .filter  $0 == true                 // true == true
  .subscribeNext  [unowned self] _ in
    self.rc.endRefreshing()             // end refreshing
  
  .addDisposableTo(self.disposeBag)

为了解决1的问题,你是对的,你可以用rx_refreshing来关闭刷新,而不是endRefreshing()

为了解决2 的问题,我认为Variable 没有必要或有用,至少在这个例子中是这样。你仍然可以使用它。另外,不需要在两个地方loadAnswers()

为了解决3 的问题,是的,您可以简化很多,并更多地使用Rx

这里的代码实际上可以工作,使用rx_refreshing,并大大简化了事情:

let initial = Observable<Void>.just(())
let refresh = rc.rx_controlEvent(.ValueChanged).map  _ in () 
let answers = Observable.of(initial, refresh)
    .merge()
    .flatMapLatest _ in self.loadAnswers() 
    .shareReplayLatestWhileConnected()

answers
    .map  _ in false 
    .bindTo(rc.rx_refreshing)
    .addDisposableTo(disposeBag)

// also use `answers` to bind to your data source, etc.

【讨论】:

这太棒了——正是需要的那种非常实用、简单的sn-ps!关于您的上一个示例,我有几个问题:我将答案设置为变量,因此我可以在需要时轻松访问它的值。在您的情况下, answers 只是一个可观察的,它观察初始值(从不更改)和刷新,即值更改时。您不需要放置过滤器 $0 == false 以便仅在刷新值为 false 时刷新吗?其次,我看到你在那里做了什么 - 只有在 loadAnswer 完成时才会设置答案。 不需要filter,因为rc.rx_controlEvent(.ValueChanged) 只会在刷新开始时发出一个事件。 您能否在示例中使用变量代替可观察的答案? 是的,它只是做你以前做的事情:使用bindTo。您也不再需要shareReplayLatestWhileConnected。不过我不认为有必要。

以上是关于RxSwift:使用 rx_refreshing 进行 uirefreshcontrol的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 RxSwift 检测双击

RxSwift基本使用

RxSwift : BehaviorRelay 代替变量使用

RxSwift:使用 DisposeBag 的最佳实践是啥?

使用 RxSwift 的问题

使用 rxswift 禁用 UITableViewCell 编辑模式