2017-06-13 11 views
3

我对RxSwift颇为陌生,并试图处理在搜索自动完成的空状态和填充状态之间切换的任务。如何正确使用switchLatest在tableview的搜索结果和空状态之间切换?

我有一个驱动程序响应文本字段文本更改长度> 0,并提出网络请求和另一个比空的搜索查询过滤器,只填充与“收藏夹”的表视图。我最初在两个观察对象上使用了merge(),但问题在于,很快清除文本会显示收藏夹,但是当最后一个获取请求返回时,它会合并并覆盖空状态。

我试着切换到switchLatest()希望当最终的clearResult被激发时它会取消之前的获取请求,但是这个可观察的东西似乎永远不会触发,我有点卡住了。任何帮助将不胜感激!

let queryFetchResultViewModel: Driver<[NewSearchResultViewModel]> = queryText 
        .filter { $0.utf8.count > 0 } 
        .throttle(0.5, scheduler: MainScheduler.instance) 
        .flatMapLatest { query in 
         appContext.placeStore.fetchPredictions(withQuery: query) 
        } 
        .map { $0.map { NewSearchResultViewModel.prediction(prediction: $0) } } 
        .asDriver(onErrorJustReturn: []) 

let queryClearResultViewModel: Driver<[NewSearchResultViewModel]> = queryText 
         .filter { $0.utf8.count == 0 } 
         .withLatestFrom(favoritePlaces.asObservable()) 
         .map { places in places.map(NewSearchResultViewModel.place) } 
         .asDriver(onErrorJustReturn: []) 

searchResultViewModel = Driver.of(queryFetchResultViewModel, queryClearResultViewModel).switchLatest() 
+0

你为什么不解决你'合并()'最初的问题?快速清除文字应取消您先前的请求。而且这是一件容易的事情 – iWheelBuy

+0

另外,为什么油门不反弹? – iWheelBuy

+0

@iWheelBuy我最初尝试合并,但我没有看到您描述的“取消之前的请求”行为。由于具有网络请求的请求所花费的时间比来自收藏场所的立即加载时间要长,所以它将稍后返回并覆盖最喜欢的场所事件。我不认为具有网络请求的流实际上合并到它的事件中,直到它的返回,所以还没有任何东西可以取消(从合并流的角度来看)。那有意义吗? – Danny

回答

1

您期待一个空字符串来影响显式过滤出空字符串的流的输出。这就是为什么你有这个问题。

- 编辑 -

为了更好地解释上述... 假设用户键入的字符,然后删除它,在你原来的代码。这是会发生的事情:角色将进入filterqueryClearResultViewModel并被滤除。它也将通过queryFetchResultViewModel的链条并获取预测。然后,用户删除,将进入过滤器queryFetchResultViewModel和被拦住的角色,同时它会走,一路过关斩将的queryClearResultViewModelsearchResultViewModel将得到最喜爱的地方...

然后,网络请求完成其传递预测结果为searchResultViewModel

此时,switchLatest将关闭queryClearResultViewModel(它将停止监听)并显示查询结果。它现在已经停止收听明确的结果流,所以没有更多的收藏会出现。

- 编辑完 -

这里是代码,将你想要做什么:

searchResultViewModel = queryText 
    .throttle(0.5, scheduler: MainScheduler.instance) 
    .flatMapLatest { query -> Observable<[NewSearchResultViewModel]> in 
     if query.isEmpty { 
      return favoritePlaces.asObservable() 
       .map { $0.map(NewSearchResultViewModel.place) } 
     } 
     else { 
      return appContext.placeStore.fetchPredictions(withQuery: query) 
       .map { $0.map { NewSearchResultViewModel.prediction(prediction: $0) } } 
     } 
    } 
    .asDriver(onErrorJustReturn: []) 

上面的代码工作,因为flatMapLatest将取消飞行fetchPredictions(withQuery:)呼叫时,新的查询来进去。即使该查询是空的。

如果你嫁给了queryText分裂成两个流,然后重新将它们组合起来,那么所有你需要做的是让queryFetchResultViewModel通过发射Observable.empty()当空查询来通过流程空文本。但即使在那里,你可能会遇到种族问题,因为取消限制,而清除不是。因此,您可能会遇到提取开始的情况,然后通过空查询显示收藏夹,然后查询完成后显示结果,然后提取流接收(延迟)清除并不执行任何操作,因为查询已完成。所以你不得不扼杀清晰的流以及抓取流...

因此,像这样(我用反跳,因为我认为这对这些事情更好地工作):

let debouncedQuery = queryText.debounce(0.5, scheduler: MainScheduler.instance) 

let queryFetchResultViewModel = debouncedQuery 
    .flatMapLatest { query -> Observable<[String]> in 
     guard !query.isEmpty else { return Observable.empty() } 
     return appContext.placeStore.fetchPredictions(withQuery: query) 
    } 
    .map { $0.map { NewSearchResultViewModel.prediction(prediction: $0) } } 
    .asDriver(onErrorJustReturn: []) 

let queryClearResultViewModel = debouncedQuery 
    .filter { $0.isEmpty } 
    .withLatestFrom(favoritePlaces.asObservable()) 
    .map { $0.map(NewSearchResultViewModel.place) } 
    .asDriver(onErrorJustReturn: []) 

searchResultViewModel = Driver.merge(queryFetchResultViewModel, queryClearResultViewModel) 
+0

啊有趣!我最终以最初的平面映射中的条件提出了建议,但我仍然不完全确定我理解了为什么switchLatest不起作用的第一点。输出流(searchResultViewModel)不执行任何过滤,只是在流之间切换,对吧?当我从一个长度为2的查询转为零时,应该不是queryFetchResultViewModel输出2个事件,然后是queryClearResultViewModel输出一个?满意你最初的建议,但仍然好奇! – Danny

+1

我编辑我的答案,一步一步解释发生了什么。 –

相关问题