RxSwift Разбивка на страницы и API - PullRequest
0 голосов
/ 29 марта 2019

Я играл с PokeApi, занимаясь практикой RxSwift. Pokeapi можно найти здесь

https://pokeapi.co/

Пример API, с которым я работаю

При поиске в pokemon вы можете установить предел того, сколько вы хотите вернуть, затем в ответе есть следующий и предыдущий параметры, чтобы вы могли продолжать идти вперед и проходить через покемона. Пример части ответа

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

{ "счетчик": 964, "рядом": "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
}

Вот часть модели представления, показывающая, что я делаю в банкомате

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

Следующий запрос зависит от первоначального запроса, поэтому, когда я нажимаю следующий раз, он все еще основан на первоначальном запросе, поэтому он просто продолжает возвращать те же данные. Я видел другие примеры кода, делающие нумерацию страниц на основе ответа API, имеющего номера страниц, но здесь нет номера страницы, все это основано на предыдущем ответе на запрос.

Любая помощь будет высоко ценится

Ответы [ 2 ]

1 голос
/ 29 марта 2019

Существует модуль RXPager , который сделает это за вас. Полезно смотреть на код, даже если вы хотите использовать собственную логику разбиения на страницы. Идея в основном в том, что вам нужно предоставить пейджеру 2 функции:

1) Способ создания следующей страницы из текущей страницы (или ноль, если это первая страница) 2) A имеет следующую функцию, чтобы определить, является ли текущая страница последней страницей.

И также наблюдаемый триггер, который вы можете привязать к пейджеру (например, расстояние contentOffset.y от вашего табличного представления снизу), который будет запускать загрузку следующей страницы (если значение next равно true).

0 голосов
/ 29 марта 2019

Я не уверен, что ваша проблема связана с 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, вы сможете получать нужные данные.

...