【问题标题】:RefreshNextPage with RxSwift使用 RxSwift 刷新下一页
【发布时间】:2018-01-12 11:23:31
【问题描述】:

我正在使用 RxSwift 进行拉动以刷新和 refreshNextPage。

目前,这是我目前工作的 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

【问题讨论】:

    标签: swift rx-swift


    【解决方案1】:

    主要思想是检查是否所有元素都已加载。我在源代码中发现你加载了 20 个部分,所以这个条件应该可以正常工作if loadedPosts &lt; 20 then stop loading new part。这里和大家分享一下基本的解决方案,大家可以随意重构(因为我不擅长RxSwift):

    MomentViewModel 你应该声明属性

    private var isAllLoaded = false
    

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

    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()
        }
    }  
    

    附:要复制/粘贴的 MomentViewModel.swift 文件。

    【讨论】:

    • 感谢您的回答! @和解。这很好用,但我不知道为什么请求下一页会跳过第二页并直接拉第三页?有什么想法吗?
    • @ZigiiWong,嗨。我检查了问题,但我没有和你一样的结果。所有请求都按原样进行:0、1、2、3...
    • 我终于解决了这个问题。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    • 2013-12-19
    • 2021-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    相关资源
    最近更新 更多