RxSwift 分页

Posted

技术标签:

【中文标题】RxSwift 分页【英文标题】:RxSwift pagination 【发布时间】:2017-04-15 07:48:40 【问题描述】:

我无法让这个解决方案发挥作用: https://github.com/liuznsn/RxMoyaPaginationNetworking

也许有人可以告诉我错误在哪里。加载变量永远不会变为假。我猜问题出在可观察的请求中,但我找不到原因。

class PaginationNetworkModel<T1: Mappable>: NSObject 

let refreshTrigger = PublishSubject<Void>()
let loadNextPageTrigger = PublishSubject<Void>()
let loading = Variable<Bool>(false)
let elements = Variable<[T1]>([])
var offset:Int = 0
let error = PublishSubject<Swift.Error>()

private let disposeBag = DisposeBag()

override init() 
    super.init()

    let refreshRequest = loading.asObservable()
        .sample(refreshTrigger)
        .flatMap  [unowned self] loading -> Observable<[T1]> in
            if loading 
                return Observable.empty()
             else 
                return self.loadData(offset: self.offset)
            
    

    let nextPageRequest = loading.asObservable()
        .sample(loadNextPageTrigger)
        .flatMap  [unowned self] loading -> Observable<[T1]> in
            if loading 
                return Observable.empty()
             else 
                self.offset += 1
                return self.loadData(offset: self.offset)
            
    

    let request = Observable
        .of(refreshRequest, nextPageRequest)
        .merge()
        .shareReplay(1)

    let response = request.flatMap  events -> Observable<[T1]> in
        request
            .do(onError:  error in
                self.error.onNext(error)
            ).catchError( error -> Observable<[T1]> in
                Observable.empty()
            )
    .shareReplay(1)

    Observable
        .combineLatest(request, response, elements.asObservable())  [unowned self] request, response, elements in
            return self.offset == 0 ? response : elements + response
        
        .sample(response)
        .bind(to: elements)
        .addDisposableTo(rx_disposeBag)

    Observable
        .of(request.map  _ in true ,
            response.map  $0.count == 0 ,
            error.map  _ in false 
        )
        .merge()
        .bind(to: loading)
        .addDisposableTo(rx_disposeBag)


func loadData(offset: Int) -> Observable<[T1]> 
    return Observable.empty()

【问题讨论】:

您是否意识到您的loadData 函数永远不会返回任何数据,这意味着response 永远不会触发? 是的。如您所见,它是通用类,如果我需要其他服务器方法,我将继承该类。我确定响应会触发,即如果我将 request.map 设置为 false 我将从服务器获取所有对象,但没有“加载”功能。 由于某种原因 request.map 在 response.map 之后调用,其中设置为 false,并立即设置为 true 因为请求,但我看不到它在响应后调用的位置 【参考方案1】:

感谢丹尼尔的帮助,这里完成了解决方案

调用示例:

goodsModel = GoodsNetworkModel()
    goodsModel.elements.asObservable().bind(to: tableView.rx.items(cellIdentifier: "Cell", cellType: StoreCell.self))  (ip, item: Goods, cell: StoreCell) in
        cell.configure(goods: item)
    .addDisposableTo(rx_disposeBag)

    tableView.rx.itemSelected.bind()  [unowned self] ip in
        self.didSelectRow(ip: ip.row)
    .addDisposableTo(rx_disposeBag)

    rx.sentMessage(#selector(UIViewController.viewDidAppear(_:)))
        .map  _ in () 
        .bind(to: goodsModel.refreshTrigger)
        .addDisposableTo(rx_disposeBag)

    tableView.rx_reachedBottom
        .map _ in ()
        .bind(to: goodsModel.loadNextPageTrigger)
        .addDisposableTo(rx_disposeBag)

型号代码:

class PaginationNetworkModel<T1: Mappable>: NSObject 

let refreshTrigger = PublishSubject<Void>()
let loadNextPageTrigger = PublishSubject<Void>()
let loading = Variable<Bool>(false)
let elements = Variable<[T1]>([])
var offset:Int = 0
let error = PublishSubject<Swift.Error>()

private let disposeBag = DisposeBag()

override init() 
    super.init()

    let refreshRequest = loading.asObservable()
        .sample(refreshTrigger)
        .flatMap  loading -> Observable<Int> in
            if loading 
                return Observable.empty()
             else 
                return Observable<Int>.create  observer in
                    observer.onNext(0)
                    observer.onCompleted()
                    return Disposables.create()
                
            
    

    let nextPageRequest = loading.asObservable()
        .sample(loadNextPageTrigger)
        .flatMap  [unowned self] loading -> Observable<Int> in
            if loading 
                return Observable.empty()
             else 
                return Observable<Int>.create  [unowned self] observer in
                    self.offset += 1
                    observer.onNext(self.offset)
                    observer.onCompleted()
                    return Disposables.create()
                
            
    

    let request = Observable
        .of(refreshRequest, nextPageRequest)
        .merge()
        .shareReplay(1)

    let response = request.flatMap  offset -> Observable<[T1]> in
        self.loadData(offset: offset)
            .do(onError:  [weak self] error in
                self?.error.onNext(error)
            ).catchError( error -> Observable<[T1]> in
                Observable.empty()
            )
        .shareReplay(1)

    Observable
        .combineLatest(request, response, elements.asObservable())  [unowned self] request, response, elements in
            return self.offset == 0 ? response : elements + response
        
        .sample(response)
        .bind(to: elements)
        .addDisposableTo(rx_disposeBag)

    Observable
        .of(request.map_ in true,
            response.map  $0.count == 0 ,
            error.map  _ in false )
        .merge()
        .bind(to: loading)
        .addDisposableTo(rx_disposeBag)


func loadData(offset: Int) -> Observable<[T1]> 
    return Observable.empty()

【讨论】:

如果我创建一个PaginationNetworkModel 然后触发它的loadNextPageTrigger,模型将尝试加载页面 1 而不会尝试加载页面 0。您确定这是正确的行为吗? 编辑我的答案,所以在调用 loadNextPageTrigger 之前我总是调用 refreshTrigger【参考方案2】:

问题出在这里:

    let refreshRequest: Observable<[T1]> = loading.asObservable()
        .sample(refreshTrigger)
        .flatMap  [unowned self] loading -> Observable<[T1]> in
            if loading 
                return Observable.empty()
             else 
                return self.loadData(offset: self.offset)
            
    

refreshRequest 在 after loadData 返回之前不会发出值。您的代码的结构方式,在refreshTrigger 上发出信号将启动网络请求,然后在网络请求完成后将 loading 设置为 true。

最好让refreshRequestnextPageRequest 返回要加载哪个页面的 Observable,然后合并它们,并在合并结果上通过网络调用调用 flatMap

【讨论】:

以上是关于RxSwift 分页的主要内容,如果未能解决你的问题,请参考以下文章

使用 RxSwift 进行分页 API 调用

RxSwift安装

RxSwift安装

RxSwift

RXSwift的一些基本交互(OC,Swift,RXSwift对比)

如何正确安装“RxSwift”模块?