Цепочка сжатие нескольких сетевых запросов с использованием Swift и объединение

#swift #combine

Вопрос:

Общий вариант использования-4 сетевых запроса

  • A. Запросы 1 и 2 должны выполняться параллельно и ждать завершения обоих
  • B. Запрос 3 выполняется после завершения 1 и 2
  • C. Запрос 4 выполняется после завершения 3

После C конечный результат должен иметь AnyPublisher тип

Я пытаюсь использовать Combine для достижения вышеуказанного, и до сих пор я могу использовать Publishers.Zip A и C с помощью flatMap . С чем я борюсь, так это с Б. Я могу сделать это, используя вложенные обработчики завершения, но не используя flatMap

Это пример кода со строками (не фактический код)

 func overallFunc(arg1: "arg1", arg2: "arg2", arg3: "arg3", arg4: "arg4" ) -gt; AnyPublisherlt;String?, Errorgt; { let pub1 = func1(arg1: arg1, arg2: arg2) let pub2 = func2(arg1: arg3, arg2: arg4)  let combinedPub = Publishers.Zip(pub1, pub2)  combinedPub  .flatMap {(response1, response2) in  return func3(arg1: response1.attribute1, arg2: response2.attribute2)  } }  

func1 , func2 и func3 все возвраты URLSession.shared.dataTaskPublisher с типом возврата говорят AnyPublisherlt;String?, Errorgt;

Сейчас я борюсь с завершением кода для overallFunc . Разработчик выдает следующую ошибку flatMap .

Type of expression is ambiguous without more context

Если я добавлю дополнительное значение в последнюю строку overallFunc , то ошибка изменится на No 'flatMap' candidates produce the expected contextual result type 'AnyPublisherlt;String?, Errorgt;'

Короче говоря, я хочу использовать flatMap результат Publishers.Zip и вернуть другого издателя, чтобы я мог добавить другого flatMap для выполнения 4-го запроса, но не могу понять правильный синтаксис и порядок действий для этого.

Комментарии:

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

2. Я совершенно уверен, что у вас есть несоответствие типа возврата. Однако это помогло бы увидеть сигнатуры методов для всех ваших методов (т. Е.: func1/2/3). Вы должны опубликовать полный пример. Я также не понимаю, что вы планируете вернуть из overallFunc. combinedPub? combinedPub.eraseToAnyPublisher()? и т. Д.

3. @Cristik Спасибо! Добавление типа возвращаемого значения помогло и дало более полезные сообщения об ошибках.

4. @Cristik Если вы предоставите свой комментарий в качестве ответа, я могу принять его как решение.

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

Ответ №1:

Я думаю, что ваша попытка запутать код устранила проблему, с которой вы столкнулись. Следующий код компилируется просто отлично:

 func func1(arg1: String, arg2: String) -gt; AnyPublisherlt;String?, Errorgt; { fatalError() } func func2(arg1: String, arg2: String) -gt; AnyPublisherlt;String?, Errorgt; { fatalError() } func func3(arg1: String, arg2: String) -gt; AnyPublisherlt;String?, Errorgt; { fatalError() } func func4(arg1: String) -gt; AnyPublisherlt;String?, Errorgt; { fatalError() }  func overallFunc(arg1: String, arg2: String, arg3: String, arg4: String) -gt; AnyPublisherlt;String?, Errorgt; {  Publishers.Zip(  func1(arg1: arg1, arg2: arg2),  func2(arg1: arg3, arg2: arg4)  )  .flatMap { (response1, response2) in  func3(arg1: response1 ?? "", arg2: response2 ?? "")  }  .flatMap { response3 in  func4(arg1: response3 ?? "")  }  .eraseToAnyPublisher() }  

Комментарии:

1. Извините, в следующий раз приведу более конкретный пример. Спасибо вам за ответ! Добавление .eraseToAnyPublisher помогло немного лучше изолировать проблему. Что решило эту проблему, так это явное добавление возвращаемого типа в flatMap закрытие.

2. Ах да. Если у вас есть более одной строки кода на плоской карте, то вам обычно приходится определять тип возвращаемого значения (если только за пределами закрытия нет чего-то, что проясняет компилятору, каким должен быть тип возвращаемого значения).

Ответ №2:

Результатом flatMap будет a String? (результат запроса 3), к которому вы затем захотите перейти map . Это map преобразует строку в четвертый запрос. Затем вы можете добавить подписчика к четвертому запросу, который будет результатом вашей общей последовательности. Так…

 pub1  .zip(pub2)  .flatMap { (response1, response2) in  func3(arg1: response1.attribute1, arg2: response2.attribute2)  }  .map {  (func3Result : String?) in  /* return publisher of 4th request */  }  .eraseToAnyPublisher()  

Результатом всего этого станет публикация 4-го запроса.