[英]How to use pagination using RxSwift and Alamofire?
I am trying to consume an api with alamofire and rxswift.我正在尝试使用 alamofire 和 rxswift 使用 api。 I have written the methods but the onNext of the observer is getting called only once.
我已经编写了方法,但是观察者的onNext只被调用了一次。 I am trying to do it with recursive call.
我正在尝试通过递归调用来做到这一点。 What is wrong with this?
这有什么问题? Api will return 10 object at a time based on the timestamp.
Api 将根据时间戳一次返回 10 个对象。 So I am checking if just returned array contains 10 objects.
所以我正在检查刚刚返回的数组是否包含 10 个对象。 If yes then there are more, if not then that's the end.
如果是,那么还有更多,如果不是,那就是结束。
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()
})
}
I put a break point on the onNext method and it seemed it's getting called only once.我在 onNext 方法上设置了一个断点,它似乎只被调用了一次。 Stuck with this for hours and RxSwift's GithubRepo example in their official github repo, I can't figure it out what they are doing.
在他们的官方 github 存储库中坚持了几个小时和 RxSwift 的 GithubRepo 示例,我无法弄清楚他们在做什么。 What can be wrong with my process?
我的流程有什么问题?
I wrote this up a while back using Promises, here it is using Singles.不久前我使用 Promises 写了这篇文章,这里使用的是 Singles。
You pass in:你传入:
It eventually returns a Single with an array of all the results.它最终返回一个包含所有结果的数组的 Single 。 It will error if any of the internal network calls error out.
如果任何内部网络调用错误,它将出错。
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
}
}
I don't think the lock is actually necessary, but I put it in just in case.我不认为锁实际上是必要的,但我把它放在以防万一。
I've improved, based on @Daniel T.'s answer , by adding next page loading trigger.根据@Daniel T. 的回答,我通过添加下一页加载触发器进行了改进。 This is useful when the next page should be loaded only when user scrolls to the bottom of
UITableView
of in similar cases.这在类似情况下仅当用户滚动到
UITableView
底部时才应加载下一页时很有用。
First page is loaded instantly upon subscribe and each subsequent page right after receiving a signal in nextPageTrigger
parameter订阅后立即加载第一页,并在
nextPageTrigger
参数中收到信号后立即加载每个后续页面
Example usage:用法示例:
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
})
Parameters:参数:
seed
- first page loading information PageKey
seed
- 第一页加载信息PageKey
requestProducer
- transforms each PageKey
to a page loading Single
requestProducer
- 将每个PageKey
转换为一个加载Single
的页面nextKeySelector
- creates next page loaging info based on data retrieved in eah page resulted from requestProducer
call. nextKeySelector
- 根据从requestProducer
调用产生的每个页面中检索到的数据创建下一个页面加载信息。 Return nil
here if there is no next page.nil
。nextPageTrigger
- after receiving first page each subsequent page is returned only after receiving a .next
signal in this observable/ 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.