我正在尝试使用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方法上设置了一个断点,似乎只调用了一次。坚持了几个小时,并将RxSwift的GithubRepo示例放在他们的官方github存储库中,我无法弄清楚他们在做什么。我的流程有什么问题?
答案 0 :(得分:1)
我前一段时间使用Promises编写了此内容,这里是使用Singles。
您传递:
它最终返回带有所有结果数组的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
}
}
我认为锁实际上并不是必需的,但是我以防万一。
答案 1 :(得分:0)
基于@Daniel T.'s answer,我已经进行了改进,增加了下一页加载触发器。当仅在类似情况下用户滚动到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
调用中导致在eah页中检索到。返回
如果没有下一页,请点击nil
。 nextPageTrigger
-之后
接收首页,随后的每页仅在
在此可观察的/ .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)
})
}