Combine and using flatMap over an array of values

Let's say I have a two types:

struct APIWidget: Codable {
  let name: String
  let imageUrl: String
}

struct Widget {
  let name: String
  let image: UIImage
}

And two publishers:

func retrieveWidgets(url: String) -> AnyPublisher<[APIWidget], Never>

func retrieveImage(imageUrl: String) -> AnyPublisher<UIImage, Never>

I'd like to compose these publishers such that I'd map the [APIWidget] returned by retrieveWidgets to [Widget]. I'm having issues conceptualizing this in terms of Combine's operators.

The thing that I'm struggling with is that for each APIWidget, I would need to flatMap onto retrieveImage, but this only seems possible if I were able to convert the AnyPublisher<[APIWidget], Never> into a AnyPublisher<APIWidget, Never>, where the latter publisher would produce a value for every item in the array produced by the first publisher.

Is there a way to do this? Am I going about this the wrong way? One thing I should mention is that the retrieveWidgets publisher necessarily returns an array of APIWidget due to how the backend supplies this data.

Not tested, just from top of my head:


retrieveWidgets(url: myURL)
  .flatMap { apiWidgets in 
    apiWidgets
      .publisher
      .flatMap { apiWidget in 
        retrieveImage(imageUrl: apiWidget.imageUrl)
          .map { image in 
            // Build Widget here
          }
      }
      .collect() // collect everything into an array. All publishers must complete first.
    }
  }

1 Like

Thank you! That looks like it should do it.