簡體   English   中英

如何使用 RxSwift 和 Alamofire 進行分頁?

[英]How to use pagination using RxSwift and Alamofire?

我正在嘗試使用 alamofire 和 rxswift 使用 api。 我已經編寫了方法,但是觀察者的onNext只被調用了一次。 我正在嘗試通過遞歸調用來做到這一點。 這有什么問題? Api 將根據時間戳一次返回 10 個對象。 所以我正在檢查剛剛返回的數組是否包含 10 個對象。 如果是,那么還有更多,如果不是,那就是結束。

func fetchPersonalization(fromList:[Personalization],timeStamp:Int) -> Observable<PersonalizationContainer>
    {


        let dictHeader = ["Accept":"application/json","regid" :  pushtoken , "os" : "ios" , "token" : token , "App-Version" : "1324" ,  "Content-Type" :  "application/json"]

        return fetchPersonalizationUtil(dictHeader: dictHeader, timeStamp: timeStamp)
            .flatMap { (perList) -> Observable<PersonalizationContainer> in

                    let persoList:[Personalization] = perList.list
                    let finalList = fromList + persoList
                    if(persoList.count==10){
                        let newTimeStamp = persoList.last!.lastModifiedAt! - 1

                        return Observable.merge(Observable.just(PersonalizationContainer(l: finalList, d: perList.data)),
                            self.fetchPersonalization(fromList:finalList,timeStamp: newTimeStamp)
                        )
                            //self.fetchPersonalization(fromList:finalList,timeStamp: newTimeStamp)



                    }else {
                        return Observable.just(PersonalizationContainer(l: finalList, d: Data()))
                    }

        }
    }

    func fetchPersonalizationUtil(dictHeader:[String:String],timeStamp:Int) -> Observable<PersonalizationContainer>
    {

        return Observable<PersonalizationContainer>.create({ (observer) -> Disposable in
            Alamofire.request("https://mranuran.com/api/hubs/personalization/laterthan/\(timeStamp)/limit/10/" ,headers: dictHeader).responseData { response in
                if let json = response.result.value {
                    //print("HUBs JSON: \(json)")

                    do {
                        let list = try JSONDecoder().decode([Personalization].self, from: json)
                        let pContainer = PersonalizationContainer(l: list, d: json)
                        print("ANURAN \(list[0].name)")
                        observer.onNext(pContainer)
                        observer.onCompleted()
                    }catch {
                        print(error)
                        observer.onError(error)
                    }

                }
                else{
                    observer.onError(response.result.error!)
                }
            }

            return Disposables.create()
        })

    }

我在 onNext 方法上設置了一個斷點,它似乎只被調用了一次。 在他們的官方 github 存儲庫中堅持了幾個小時和 RxSwift 的 GithubRepo 示例,我無法弄清楚他們在做什么。 我的流程有什么問題?

不久前我使用 Promises 寫了這篇文章,這里使用的是 Singles。

你傳入:

  1. 用於進行第一次網絡調用的種子。
  2. pred 將給出最近一次調用的結果,並產生一個參數來進行下一次網絡調用,如果完成則為 nil。 (如果需要另一個調用,您可以在這里檢查計數並返回下一個時間戳。)
  3. 進行網絡調用的生產者。

它最終返回一個包含所有結果的數組的 Single 。 如果任何內部網絡調用錯誤,它將出錯。

func accumulateWhile<T, U>(seed: U, pred: @escaping (T) -> U?, producer: @escaping (U) -> Single<T>) -> Single<[T]> {
    return Single.create { observer in
        var disposable = CompositeDisposable()
        var accumulator: [T] = []
        let lock = NSRecursiveLock()
        func loop(_ u: U) {
            let product = producer(u)
            let subDisposable = product.subscribe { event in
                lock.lock(); defer { lock.unlock() }
                switch event {
                case let .success(value):
                    accumulator += [value]
                    if let u = pred(value) {
                        loop(u)
                    }
                    else {
                        observer(.success(accumulator))
                    }
                case let .error(error):
                    observer(.error(error))
                }
            }
            _ = disposable.insert(subDisposable)
        }
        loop(seed)
        return disposable
    }
}

我不認為鎖實際上是必要的,但我把它放在以防萬一。

根據@Daniel T. 的回答,我通過添加下一頁加載觸發器進行了改進。 這在類似情況下僅當用戶滾動到UITableView底部時才應加載下一頁時很有用。

訂閱后立即加載第一頁,並在nextPageTrigger參數中收到信號后立即加載每個后續頁面

用法示例:

let contents = loadPagesLazily(
    seed: 1,
    requestProducer: { (pageNumber: Int) -> Single<ResponseContainer<[Content]>> in
        return dataSource.loadContent(page: Id, pageSize: 20)
    },
    nextKeySelector: { (responseContainer: ResponseContainer<[Content]>) -> Meta? in
        let hasMorePages = responseContainer.meta.currentPage < responseContainer.meta.lastPage

        return hasMorePages ? responseContainer.meta.currentPage + 1 : nil
    },
    nextPageTrigger: loadMoreTrigger
)

return contents
    .scan([]], accumulator: { (accumulator, nextPageContainer) -> SearchResults in
        accumulator + nextPageContainer.data
    })

參數:

  • seed - 第一頁加載信息PageKey
  • requestProducer - 將每個PageKey轉換為一個加載Single的頁面
  • nextKeySelector - 根據從requestProducer調用產生的每個頁面中檢索到的數據創建下一個頁面加載信息。 如果沒有下一頁,則在此處返回nil
  • nextPageTrigger - 接收第一頁后,每個后續頁僅在此 observable 中接收到.next信號后返回/
func loadPagesLazily(
    seed: PageKey,
    requestProducer: @escaping (PageKey) -> Single<Page>,
    nextKeySelector: @escaping (Page) -> PageKey?,
    nextPageTrigger: Observable<Void>
) -> Observable<Page> {
    return requestProducer(seed)
        .asObservable()
        .flatMap({ (response) -> Observable<Page>  in
            let nextPageKey = nextKeySelector(response)

            let nextPageLoader: Observable<Page> = nextPageKey
                .map { (meta) -> Observable<Page> in
                    nextPageTrigger.take(1)
                        .flatMap { (_) -> Observable<Page> in
                            loadPagesLazily(
                                seed: meta,
                                requestProducer: requestProducer,
                                nextKeySelector: nextKeySelector,
                                nextPageTrigger: nextPageTrigger
                            )
                        }
                } ?? Observable.empty()

            // Concatenate self and next page recursively
            return Observable
                .just(response)
                .concat(nextPageLoader)
        })
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM