2016-02-11 4 views
4

Давайте представим, что мы имеем массив экземпляров AnObject и должны иметь следующую последовательность действий для выполнения:RxSwift: цепочки несколько действий

  • передавать объекты бакэнду через отдельные вызовы
  • после шага 1 отделок хранить этот массив в БД в пакетном режиме
  • после шага 2 отделки дополнительной обработки для каждого элемента

, и мы хотим получить сигнал только после выполнения всех этих шагов (или произошла ошибка). Каков правильный способ достичь этого через RxSwift и действительно ли это возможно?

Пожалуйста, найдите мои прототипы ниже. К сожалению, я не придумал пример кода для цепочки, так что демо не будет.

func makeAPIRequest(object: AnObject) -> Observable<Void> { 
    ... 
} 

func storeData(data: [AnObject]) -> Observable<Void> { 
    ... 
} 

func additionalProcessing(object: AnObject) -> Observable<Void> { 
    ... 
} 

func submitData() 
{ 
    let data: [AnObject] = ...; 

    let apiOperations = data.map{ makeAPIRequest($0) }; 
    let storageOperation = storeData(data); 
    let processingOperations = data.map{ additionalProcessing($0) }; 

    ... // some code to chain steps 1-3 
    .subscribe { (event) -> Void in 
     // should be called when operations from step 3 finished 
    }.addDisposableTo(disposeBag); 
} 

ответ

8

Давайте предположим, что оба makeAPIRequest и additionalProcessing возвращают Observable<SomeNotVoidType> и storeData принимает массив в качестве аргумента и возвращает Observable<Array>. Таким образом, вы можете:

Сначала создайте массив из Observables, представляющий отправку отдельных объектов на бэкэнд. Затем с помощью метода toObservable, так что результирующие сигналы могут быть преобразованы в дальнейшем:

let apiOperations = data.map{ makeAPIRequest($0) }.toObservable()

затем использовать merge оператор, который будет сделать Observable, который завершает только тогда, когда все API вызовы завершена. Вы можете также использовать toArray оператор, который поставит результаты API вызовов в один массив:

let resultsArray = apiOperations.merge().toArray()

Это поможет вам Observable<Array<ApiResult>>, который будет посылать одно Next событие, когда все операции API успешно завершена. Теперь вы можете сохранять результаты в базе данных:

let storedResults = resultsArray.flatMap { storeDatabase($0) } 

Затем вы снова хотите сделать Observables для каждого элемента массива, так что они будут представлять дополнительную обработку. Обратите внимание, что вам нужно использовать flatMap и flatMapLates, иначе вы получите вложенные наблюдаемые значения, например Observable<Observable<SomeType>>.

let additionalProcessingResults = storedResults.flatMap { 
     return $0.map(additionalProcessing).toObservable() 
    }.flatMapLatest { return $0 } 

Затем, вы можете подписаться на успешное завершение дополнительной обработки (или вы можете сделать что-то с его индивидуальными результатами):

additionalProcessingResults.subscribe { (event) -> Void in 
     // should be called when operations from step 3 finished 
    }.addDisposableTo(disposeBag); 

Обратите внимание, что вам не нужны все промежуточные переменные, Я просто оставил их, чтобы описать все этапы.

+0

Спасибо, Michał, это очень полезно! Могу ли я спросить, есть ли какие-либо источники/примеры, из которых я могу найти связанные с ними практики RxSwift (кроме документации)? – NikGreen

+0

Я работал с Reactive Cocoa 2.x, который имеет довольно похожий API (но в ObjC) и множество доступных примеров.К сожалению, для RxSwift еще не так много, возможно, взгляните на приложение Eidolon: https://github.com/artsy/eidolon. Кроме того, я обнаружил, что игровая площадка RxSwift очень полезна, вы можете экспериментировать с Observables легко: https://github.com/ReactiveX/RxSwift#playgrounds –