Последовательная плоская карта RxSwift с запросом Moya

В настоящее время у меня есть следующий код

func updateItems(_ observable: Observable<ContainingEntity>) -> Observable<ContainingEntity>{
    return observable
        .concatMap({ (containingEntity) -> Observable<ContainingEntity> in
            guard let itemEntity = orderEntity.itemEntity,
                itemEntity.name.count == 0 else{
                    return Observable.just(entity)
            }

            print("Need to fetch name of item #\(itemEntity.id)")

            return RestManager.getDetailOf(item: itemEntity)
                .flatMap({ (updatedItemEntity) -> Observable<ContainingEntity> in
                    var updatedContainingEntity = containingEntity
                    containingEntity.itemEntity = updatedItemEntity
                    print("Fetched item name: \(itemEntity.name)")
                    return Observable.just(containingEntity)
                })
        })
}

По сути, мне нужно убедиться, что itemEntity каждого ContainEntity имеет имя, и, если нет, запросить его у Moya.

Но я сталкиваюсь со следующим типом вывода из двух отпечатков:

  • Необходимо получить название предмета №1
  • Необходимо получить название предмета №2
  • Необходимо получить название предмета №3
  • Название полученного предмета: Name1
  • Название полученного предмета: Name2
  • Название полученного товара: Name3

Это означает, что операции в моем concatMap выполняются параллельно, чего я не хочу из-за избыточности запросов и некоторой системы кеширования, которую я здесь не показал: у меня может быть 30-кратный одинаковый идентификатор элемента, и я не хочу его запрашивать 30 раз.

Я ожидаю:

  • Необходимо получить название предмета №1
  • Название полученного предмета: Name1
  • Необходимо получить название предмета №2

  • Название полученного предмета: Name2

  • Необходимо получить название предмета №3
  • Название полученного товара: Name3

Как я могу исправить эту проблему? Большое спасибо за Вашу помощь.

ОБНОВЛЕНИЕ:

Сейчас я использую какой-то простой буфер, который сохраняет ItemEntities, которые необходимо обновить, и назначает эти элементы следующим ContainEntities с тем же идентификатором. Это не позволяет Мойе выполнять один и тот же запрос несколько раз.

Он работает отлично, но мне не очень нравится идея этого механизма, внешнего по отношению к RX ...


person y00rn    schedule 19.04.2018    source источник


Ответы (1)


Я думаю, что использование Variable или BehaviorSubject для управления последовательной загрузкой может сработать (код ниже).

Однако вы можете захотеть переосмыслить архитектуру загрузки, потому что при использовании этого кода время загрузки может быть неоптимальным.

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

Я не тестировал приведенный ниже код, поэтому он может даже не компилироваться ???? - если он работает, сообщите мне и примите ответ.

func updateItems(_ observable: Observable<ContainingEntity>) -> Observable<ContainingEntity>{
  let trigger = BehaviorSubject<Int>(value: 0)
  let sequential = Observable.zip(observable, trigger) { return $0.0 }
  return sequential
    .concatMap({ (containingEntity) -> Observable<ContainingEntity> in
      guard let itemEntity = orderEntity.itemEntity,
        itemEntity.name.count == 0 else{
          return Observable.just(entity)
      }

      print("Need to fetch name of item #\(itemEntity.id)")

      return RestManager.getDetailOf(item: itemEntity)
        .flatMap({ (updatedItemEntity) -> Observable<ContainingEntity> in
          var updatedContainingEntity = containingEntity
          containingEntity.itemEntity = updatedItemEntity
          print("Fetched item name: \(itemEntity.name)")
          trigger.onNext(0)
          return Observable.just(containingEntity)
        })
    })
}
person Juan Carlos Méndez    schedule 25.04.2018
comment
Большое спасибо за очень интересный ответ. Но я на самом деле попробовал это, и не только немного разочаровывает использование такого сложного механизма (потому что у меня такая же проблема в 5 менеджерах в моем приложении), но он также блокируется, если Observable ‹ContainEntity› пуст! - person y00rn; 25.04.2018
comment
Имеет смысл @ y00rn - я вижу обновление вашего вопроса об использовании буфера. - person Juan Carlos Méndez; 25.04.2018