RxSwift分页和API问题

时间:2019-03-29 11:03:51

标签: swift rx-swift

在进行一些RxSwift练习时,我一直在玩PokeApi。可以在这里找到Pokeapi

https://pokeapi.co/

我正在使用的api示例

在搜索口袋妖怪时,您可以设置要返回的数量的限制,然后在响应中,存在下一个和上一个参数,因此您可以继续前进并通过口袋妖怪前进。部分回复示例

https://pokeapi.co/api/v2/pokemon/?limit=20

  

{“ count”:964,“ next”:“ https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20”,“ previous”:null,“ results”:....

在我的控制器中,有一个文本字段,他们可以在其中输入每页要返回多少个神奇宝贝,然后当他们点击搜索时,结果将返回到表格中,并且他们可以点击下一个和上一个来循环浏览这些页面。我的模特看起来像这样

struct PokemonSearchData: Codable {
    let next: String?
    let previous: String?
    let results: [PokemonResultsData]
}

struct PokemonResultsData: Codable {
    let name: String
    let url: String
}

这是显示我在做atm的视图模型的一部分

extension PokeListViewModel: ViewModelType {
    struct Input {
        let limitText: Observable<String>
        let startRequest: PublishSubject<Void>
        let nextTap: Observable<Void>
        let previousTap: Observable<Void>
        let selectedPokemon: Observable<PokemonResultsData>
    }

    struct Output {
        let responseData: Observable<PokemonSearchData>
        let errors: Driver<Error>
    }

    func transform(input: PokeListViewModel.Input) -> PokeListViewModel.Output {
        let request = input.startRequest
            .withLatestFrom(input.limitText)
            .flatMap { text in
            self.service.fetchPokemon(limit: text).materialize()
        }.share()

        let searchResponse = request.map{$0.element}.filterNil()
        let searchError = request.map{$0.error}.asDriver(onErrorJustReturn: RxError.unknown).filterNil()

        let nextURL = searchResponse.map{$0.next}.filterNil()

        // handle next request and errors
        let nextRequest = input.nextTap.withLatestFrom(nextURL).flatMap { nextURL in
            self.service.cyclePokemon(stringURL: nextURL).materialize()
            }.share()
        let nextResponse = nextRequest.map{$0.element}.filterNil()
        let nextError = nextRequest.map{$0.error}.asDriver(onErrorJustReturn: RxError.unknown).filterNil()

        let mergedResponses = Observable.merge(searchResponse, nextResponse)
        let mergedErrors = Driver.merge(searchError, nextError)

// do the same thing for previous response, just cut it out here so less code to paste, but the logic is the same

        return Output(responseData: mergedResponses,
                      errors: mergedErrors)
    }

下一个请求取决于初始请求,因此当我再次按下next时,它仍然基于初始请求,因此它只会返回相同的数据。我已经看到其他代码示例基于具有页面编号的api响应进行分页,但是这里没有页面编号,这全部基于先前的请求响应。

任何帮助将不胜感激

2 个答案:

答案 0 :(得分:1)

有一个RXPager吊舱将为您完成此操作。即使您想拥有分页逻辑,查看代码也很有用。基本上,您需要为寻呼机提供2个功能:

1)一种从当前页面生成下一页的方法(如果为第一页,则为nil) 2)具有下一个功能,以确定当前页面是否为最后一页。

还有一个可观察到的触发器,您可以将其绑定到寻呼机(例如,tableview的contentOffset.y与底部的距离),这将触发下一个页面加载(如果next为true)。

答案 1 :(得分:0)

我不确定您的问题是否与RxSwift有关。据我了解,拨打电话时需要使用offset参数。例如,此请求:

  

https://pokeapi.co/api/v2/pokemon/?limit=4

生成以下响应:

{
  "count": 964,
  "next": "https://pokeapi.co/api/v2/pokemon/?offset=4&limit=4",
  "previous": null,
  "results": [
    {
      "name": "bulbasaur",
      "url": "https://pokeapi.co/api/v2/pokemon/1/"
    },
    {
      "name": "ivysaur",
      "url": "https://pokeapi.co/api/v2/pokemon/2/"
    },
    {
      "name": "venusaur",
      "url": "https://pokeapi.co/api/v2/pokemon/3/"
    },
    {
      "name": "charmander",
      "url": "https://pokeapi.co/api/v2/pokemon/4/"
    }
  ]
}

看看next键的值是您接下来应该点击的URL吗?

"next": "https://pokeapi.co/api/v2/pokemon/?offset=4&limit=4",

我相信,只要您跟踪offset的值,就可以接收所需的数据。