Swift 如何在反应式扩展中组合两个观察值以对结果进行分页?

Swift 如何在反应式扩展中组合两个观察值以对结果进行分页?,swift,reactive-programming,observable,rx-swift,reactivex,Swift,Reactive Programming,Observable,Rx Swift,Reactivex,我正在尝试使用RxSwift在iOS应用程序中开发分页系统。用例很简单:用户可以在搜索字段中输入文本,应用程序执行分页请求。当他更改值时,在第一页执行一个新的请求(这意味着必须将可观察值重置为1)。如果用户清除搜索字段(或输入少于2个字符的文本),则清除结果列表并重置当前页面。当用户滚动到列表底部时,将获取下一页 这不是swift或iOS特定的情况,我想它可以使用RxKotlin或RxJs或任何其他反应式扩展以相同的方式编写 我目前的尝试是为文本和当前页面设置一个observable,并将它们组

我正在尝试使用RxSwift在iOS应用程序中开发分页系统。用例很简单:用户可以在搜索字段中输入文本,应用程序执行分页请求。当他更改值时,在第一页执行一个新的请求(这意味着必须将可观察值重置为1)。如果用户清除搜索字段(或输入少于2个字符的文本),则清除结果列表并重置当前页面。当用户滚动到列表底部时,将获取下一页

这不是swift或iOS特定的情况,我想它可以使用RxKotlin或RxJs或任何其他反应式扩展以相同的方式编写

我目前的尝试是为文本和当前页面设置一个observable,并将它们组合起来,以便使用这两个参数执行请求。 我已经成功地完成了我想要的工作,但是使用了全局属性来存储当前查询和当前页面。我想找到一种方法,只使用可观测物发出的值,而不必维护它们(我想代码会更简洁,更易于阅读和理解)

这是我目前的代码:

    // 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
    }
然后我有两个请求被执行


我是否误用了Rx?

我不会使用
CombineTest
。您的页码取决于当前的搜索文本,因此您应该使用
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(())
let dispebag=dispebag()
让searchText=PublishSubject()//搜索字段文本
让NewPageRequired=PublishSubject()//在需要新页面时激发
结构请求页{
让查询:字符串
让页面:Int
}
let requestNeeded=searchText.asObservable()
.flatmap最新版本{text in
newPageNeeded.asObservable()
.startWith(())
.scan(请求页面(查询:文本,页面:0)){request,\ in
返回请求页面(查询:文本,页面:request.page+1)
}
}
请求需要
.subscribebenext{print($0)}
.addDisposableTo(disposeBag)
searchText.onNext(“A”)
searchText.onNext(“B”)
newPageRequired.onNext(())
searchText.onNext(“C”)
newPageRequired.onNext(())
newPageRequired.onNext(())
这将输出:

(请求第1页)(查询:“A”,第1页)
(请求第1页)(查询:“B”,第1页)
(请求第1页)(查询:“B”,第2页)
(请求第1页)(查询:“C”,第1页)
(请求第1页)(查询:“C”,第2页)
(第1页)(查询:“C”,第3页)


这太完美了!
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(())