Swift Combine: How to create a single publisher from a list of publishers?

后端 未结 3 1648
感情败类
感情败类 2021-02-04 00:24

Using Apple\'s new Combine framework I want to make multiple requests from each element in a list. Then I want a single result from a reduction of all the the responses. Basical

3条回答
  •  别跟我提以往
    2021-02-04 01:02

    I think that Publishers.MergeMany could be of help here. In your example, you might use it like so:

    func createIngredients(ingredients: [Ingredient]) -> AnyPublisher {
        let publishers = ingredients.map(createIngredient(ingredient:))
        return Publishers.MergeMany(publishers).eraseToAnyPublisher()
    }
    

    That will give you a publisher that sends you single values of the Output.

    However, if you specifically want the Output in an array all at once at the end of all your publishers completing, you can use collect() with MergeMany:

    func createIngredients(ingredients: [Ingredient]) -> AnyPublisher<[CreateIngredientMutation.Data], Error> {
        let publishers = ingredients.map(createIngredient(ingredient:))
        return Publishers.MergeMany(publishers).collect().eraseToAnyPublisher()
    }
    

    And either of the above examples you could simplify into a single line if you prefer, ie:

    func createIngredients(ingredients: [Ingredient]) -> AnyPublisher {
        Publishers.MergeMany(ingredients.map(createIngredient(ingredient:))).eraseToAnyPublisher()
    }
    

    You could also define your own custom merge() extension method on Sequence and use that to simplify the code slightly:

    extension Sequence where Element: Publisher {
        func merge() -> Publishers.MergeMany {
            Publishers.MergeMany(self)
        }
    }
    
    func createIngredients(ingredients: [Ingredient]) -> AnyPublisher {
        ingredients.map(createIngredient).merge().eraseToAnyPublisher()
    }
    

提交回复
热议问题