2016-09-02 3 views
1

私はRxSwiftを使ってiOSアプリケーションでページネーションシステムを開発しようとしています。ユースケースは単純です:ユーザは検索フィールドにテキストを入力することができ、アプリケーションはページ付けされたリクエストを実行します。彼が値を変更すると、最初のページで新しいリクエストが実行されます(つまり、オブザーバブルの値を1にリセットする必要があります)。ユーザーが検索フィールドをクリアする(または2文字未満のテキストを入力する)と、結果のリストがクリアされ、現在のページがリセットされます。ユーザーがリストの一番下までスクロールすると、次のページが取得されます。Reagent Extensionsで2つのオブザーバブルを結合して結果をページ付けする方法は?

これは迅速またはiOS固有のケースではなく、RxKotlinまたはRxJsまたは他の反応拡張を使用して同じ方法で記述できるとします。

私の現在の試みは、両方のパラメータでリクエストを実行するために、現在のページのためのオブザーバブルと現在のページのオブザーバブルを設定し、それらを組み合わせることです。 私は探しているものを正確に行うことに成功しましたが、現在のクエリと現在のページを格納するためにグローバル属性を使用しています。私は、オブザーバブルを維持することなく観測値によって放出された値だけを使用する方法を見つけたいと思います(コードはより簡潔で読みやすく理解しやすいでしょう)。ここで

は私の現在のコードです:

// self.nextPage is a Variable<Int> 
    let moreObs: Observable<Int> = self.nextPage.asObservable() 
     .distinctUntilChanged() // Emit only if page has changed. 

    // self.searchTextObservable is a PublishedSubject<String> that receives the values from the textfield 
    let searchObs: Observable<String> = self.searchTextObservable 
     .throttle(0.4, scheduler: MainScheduler.instance) // Wait 400ms when the user stops writing. 
     .distinctUntilChanged() // Emit only if query has changed. 

    self.resultsObservable = Observable 
     .combineLatest(searchObs, moreObs) { query, page in 
      return ["q": query, "p": "\(page)"] 
     } 
     .subscribeOn(MainScheduler.instance) // Emit on main thread. 
     .observeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Background)) // Perform on background thread. 
     .map { params in 
      if params["q"]!.characters.count > 2 { 
       return params 
      } 
      return [:] 
     } 
     .flatMap { params in 
      return params.isEmpty ? 
      Observable.of([]) : 
      self.search(params) 
     } 
     .map { results in 
      if results.count > 0 { 
       self.results.appendContentsOf(results) 
      } else { 
       self.results = [] 
      } 
      return self.results 
    } 

これまでのところ、動作しないだけで機能がNEXTPAGEの値にリセット動作です。 searchObsを発したときに、私は1にそれを強制する場合:

let searchObs: Observable<String> = self.searchTextObservable 
     .throttle(0.4, scheduler: MainScheduler.instance) // Wait 400ms when the user stops writing. 
     .distinctUntilChanged() // Emit only if query has changed. 
     .map {query in 
      self.nextPage.value = 1 
      return query 
     } 

をそれから私が実行されている2つの要求を持っています。

Rxを乱用していますか?

答えて

2

私はcombineLatestを使用しません。あなたのページ番号はあなたの現在の検索テキストに依存しているので、flatMapLatestと連鎖させるべきです。そうすれば、あなたは自分自身の状態を維持する責任を負うのではなく、オペレーター連鎖でそれをリセットすることができます。

let disposeBag = DisposeBag() 

let searchText = PublishSubject<String>() // search field text 
let newPageNeeded = PublishSubject<Void>() // fires when a new page is needed 

struct RequestPage { 
    let query: String 
    let page: Int 
} 

let requestNeeded = searchText.asObservable() 
    .flatMapLatest { text in 
     newPageNeeded.asObservable() 
      .startWith(()) 
      .scan(RequestPage(query: text, page: 0)) { request, _ in 
       return RequestPage(query: text, page: request.page + 1) 
      } 
    } 

requestNeeded 
    .subscribeNext { print($0) } 
    .addDisposableTo(disposeBag) 

searchText.onNext("A") 

searchText.onNext("B") 
newPageNeeded.onNext(()) 

searchText.onNext("C") 
newPageNeeded.onNext(()) 
newPageNeeded.onNext(()) 

この意志出力:

(RequestPage#1)(クエリ: "A"、ページ:1)
(RequestPage#1)(クエリ: "B"、ページ:1 (クエリ: "C"、ページ:1)
(クエリ: "C"、ページ:1)
(クエリ: "B"、ページ:2)
、ページ:2)
(リクエストページ#1)(クエリ: "C"、ページ:3)

+0

これは完璧です! – obo

関連する問題