使用RxSwift的RefreshNextPage

时间:2018-01-12 11:23:32

标签: swift rx-swift

我正在使用RxSwift进行刷新和刷新下一页。

目前,这是我目前工作的viewModel:

public final class MomentViewModel {
// Property
let refreshTrigger = PublishSubject<Void>()
let loadNextPageTrigger = PublishSubject<Void>()
let loading = Variable<Bool>(false)
let posts = Variable<[Post]>([])
var pageIndex: Int = 0
let error = PublishSubject<Swift.Error>()
private let disposeBag = DisposeBag()

public init() {

    let refreshRequest = loading.asObservable()
        .sample(refreshTrigger)
        .flatMap { loading -> Observable<Int> in
            if loading {
                return Observable.empty()
            } else {
                return Observable<Int>.create { observer in
                    self.pageIndex = 0
                    print("reset page index to 0")
                    observer.onNext(0)
                    observer.onCompleted()
                    return Disposables.create()
                }
            }
    }
    .debug("refreshRequest", trimOutput: false)

    let nextPageRequest = loading.asObservable()
        .sample(loadNextPageTrigger)
        .flatMap { loading -> Observable<Int> in
            if loading {
                return Observable.empty()
            } else {
                return Observable<Int>.create { [unowned self] observer in
                    self.pageIndex += 1
                    print(self.pageIndex)
                    observer.onNext(self.pageIndex)
                    observer.onCompleted()
                    return Disposables.create()
                }
            }
    }
    .debug("nextPageRequest", trimOutput: false)

    let request = Observable.merge(refreshRequest, nextPageRequest)
        .debug("Request", trimOutput: false)

    let response = request.flatMapLatest { page in
            RxAPIProvider.shared.getPostList(page: page).materialize()
        }
        .share(replay: 1)
        .elements()
        .debug("Response", trimOutput: false)

    Observable
        .combineLatest(request, response, posts.asObservable()) { request, response, posts in
            return self.pageIndex == 0 ? response : posts + response
        }
        .sample(response)
        .bind(to: posts)
        .disposed(by: disposeBag)

    Observable
        .merge(request.map{ _ in true },
            response.map { _ in false },
            error.map { _ in false })
        .bind(to: loading)
        .disposed(by: disposeBag)
    }
}

refreshTriggerloadNextPageTrigger绑定到不同的目标赞:

self.tableView.rx_reachedBottom
        .map { _ in () }
        .bind(to: self.viewModel.loadNextPageTrigger)
        .disposed(by: disposeBag)

self.refreshControl.rx.controlEvent(.valueChanged)
        .bind(to: self.viewModel.refreshTrigger)
        .disposed(by: disposeBag)


self.rx.sentMessage(#selector(UIViewController.viewWillAppear(_:)))
        .map { _ in () }
        .bind(to: viewModel.refreshTrigger)
        .disposed(by: disposeBag)

问题:

当我将tableView滚动到底部并触发loadNextPageTrigger时,一切正常。

但是,如果下一个请求中没有更多数据,将无限触发loadnextPageTrigger。 任何帮助将不胜感激。

您可以在此处下载Demo

1 个答案:

答案 0 :(得分:1)

主要思想是检查是否所有元素都已加载。我在源代码中发现你加载了20个部分,所以这个条件应该可以正常if loadedPosts < 20 then stop loading new part。在这里,我与您分享您可以根据需要重构的基本解决方案(因为我不擅长RxSwift):

MomentViewModel中,您应声明属性

private var isAllLoaded = false

如果加载了所有值,则设置为true。然后,您应该检查响应设置正确[Post]的每个isAllLoaded

Observable
    .combineLatest(request, response, posts.asObservable()) { request, response, posts in
        self.isAllLoaded = response.count < 20 // here the check
        return self.pageIndex == 0 ? response : posts + response
    }
    .sample(response)
    .bind(to: posts)
    .disposed(by: disposeBag)

然后在nextPageRequest中,如果所有部分都已加载,则应返回.empty()观察者:

if loading {
    return Observable.empty()
} else {
    guard !self.isAllLoaded else { return Observable.empty() }

    return Observable<Int>.create { [unowned self] observer in
        self.pageIndex += 1
        print(self.pageIndex)
        observer.onNext(self.pageIndex)
        observer.onCompleted()
        return Disposables.create()
    }
}  

P.S。要复制/粘贴的MomentViewModel.swift文件。