I'm trying to compose a nested publisher chain in combine with Swift and I'm stumped. My current code starts throwing errors at the .flatMap line, and I don't know why. I've been trying to get it functional but am having no luck.
What I'm trying to accomplish is to download a TrailerVideoResult and decode it, grab the array of TrailerVideo objects, transform that into an array of YouTube urls, and then for each YouTube URL get the LPLinkMetadata. The final publisher should return an array of LPLinkMetadata objects. Everything works correctly up until the LPLinkMetadata part.
EDIT: I have updated the loadTrailerLinks function. I originally forgot to remove some apart of it that was not relevant to this example.
You will need to import "LinkPresentation". This is an Apple framework for to fetch, provide, and present rich links in your app.
The error "Type of expression is ambiguous without more context" occurs at the very last line (eraseToAnyPublisher).
func loadTrailerLinks() -> AnyPublisher<[LPLinkMetadata], Error>{
return URLSession.shared.dataTaskPublisher(for: URL(string: "Doesn't matter")!)
.tryMap() { element -> Data in
guard let httpResponse = element.response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return element.data
}
.decode(type: TrailerVideoResult.self, decoder: JSONDecoder(.convertFromSnakeCase))
.compactMap{ $0.results }
.map{ trailerVideoArray -> [TrailerVideo] in
let youTubeTrailer = trailerVideoArray.filter({$0.site == "YouTube"})
return youTubeTrailer
}
.map({ youTubeTrailer -> [URL] in
return youTubeTrailer.compactMap{
let urlString = "https://www.youtube.com/watch?v=\($0.key)"
let url = URL(string: urlString)!
return url
}
})
.flatMap{ urls -> [AnyPublisher<LPLinkMetadata, Never>] in
return urls.map{ url -> AnyPublisher <LPLinkMetadata, Never> in
return self.getMetaData(url: url)
.map{ metadata -> LPLinkMetadata in
return metadata
}
.eraseToAnyPublisher()
}
}
.eraseToAnyPublisher()
}
func fetchMetaData(url: URL) -> AnyPublisher <LPLinkMetadata, Never> {
return Deferred {
Future { promise in
LPMetadataProvider().startFetchingMetadata(for: url) { (metadata, error) in
promise(Result.success(metadata!))
}
}
}.eraseToAnyPublisher()
}
struct TrailerVideoResult: Codable {
let results : [TrailerVideo]
}
struct TrailerVideo: Codable {
let key: String
let site: String
}