Combine framework: how to process each element of array asynchronously before proceeding

后端 未结 2 1673
一整个雨季
一整个雨季 2021-01-04 09:46

I\'m having a bit of a mental block using the iOS Combine framework.

I\'m converting some code from \"manual\" fetching from a remote API to using Combine. Basically

2条回答
  •  余生分开走
    2021-01-04 10:27

    Using the accepted answer, I wound up with this structure:

    head // [Entity]
        .flatMap { entities -> AnyPublisher in
            Publishers.Sequence(sequence: entities).eraseToAnyPublisher()
        }.flatMap { entity -> AnyPublisher in
            self.makeFuture(for: entity) // [Derivative]
                .flatMap { derivatives -> AnyPublisher in
                    Publishers.Sequence(sequence: derivatives).eraseToAnyPublisher()
                }
                .flatMap { derivative -> AnyPublisher in
                    self.makeFuture(for: derivative).eraseToAnyPublisher() // Derivative2
            }.collect().map { derivative2s -> Entity in
                self.configuredEntity(entity, from: derivative2s)
            }.eraseToAnyPublisher()
        }.collect()
    

    That has exactly the elegant tightness I was looking for! So the idea is:

    We receive an array of something, and we need to process each element asynchronously. The old way would have been a DispatchGroup and a for...in loop. The Combine equivalent is:

    • The equivalent of the for...in line is flatMap and Publishers.Sequence.

    • The equivalent of the DispatchGroup (dealing with asynchronousness) is a further flatMap (on the individual element) and some publisher. In my case I start with a Future based on the individual element we just received.

    • The equivalent of the right curly brace at the end is collect(), waiting for all elements to be processed and putting the array back together again.

    So to sum up, the pattern is:

    1. flatMap the array to a Sequence.
    2. flatMap the individual element to a publisher that launches the asynchronous operation on that element.
    3. Continue the chain from that publisher as needed.
    4. collect back into an array.

    By nesting that pattern, we can take advantage of Swift scoping rules to keep the thing we need to process in scope until we have acquired enough information to produce the processed object.

提交回复
热议问题