0

I would like to wait for data from all elements and combine them into one result:

Item: AnyPublisher <Int, Swift.Error>
Array: AnyPublisher <[Result<Int, Swift.Error>], Never>

Can this be done somehow? I've tried using Zip and Merge - but I couldn't get the desired result.

Example:

func createItem(num: Int) -> AnyPublisher<Int, Swift.Error> {
    Just(num)
        .setFailureType(to: Swift.Error.self)
        .eraseToAnyPublisher()
}
func createItems(nums: [Int]) -> AnyPublisher<[Result<Int, Swift.Error>], Never> {
    Publishers.MergeMany(nums.map { self.createItem(num: $0) } )
        .collect()
        .eraseToAnyPublisher()
}

Function but "createItems" does not work

  • Possible duplicate of https://stackoverflow.com/questions/61841254/combine-framework-how-to-process-each-element-of-array-asynchronously-before-pr – matt Feb 22 '21 at 21:00

1 Answers1

1

Looks like you want to generate an array of results - whether a value or an error - emitted by each publisher for each array value.

MergeMany + Collect is the right approach here. MergeMany will complete only when all its input publishers complete, and .collect() will for for that completion event before emitting.

Using your example:

func createItems(nums: [Int]) -> AnyPublisher<[Result<Int, Error>], Never> {

    let publishers = nums.map { v -> AnyPublisher<Result<Int, Error>, Never> in
        createItem(num: v) // AnyPublisher<Int, Error>
           .first() // ensure a single result
           .map { .success($0) } // map value to .success result
           .catch { Just(.failure($0)) } // map error to .failure result
           .eraseToAnyPublisher()
    }

    return Publishers.MergeMany(publishers)
        .collect() // wait for MergeMany to complete
        .eraseToAnyPublisher()
}

New Dev
  • 48,427
  • 12
  • 87
  • 129