Encadenando editores de cosechadora rápida y recibiendo cada resultado
En el siguiente ejemplo, estoy haciendo una solicitud de red para cargar diferentes géneros de películas y luego lo uso para cargar todas las películas. El fregadero solo devuelve los resultados de la película. ¿Cómo puedo recibir tanto los géneros como las películas?
struct Genre: Codable, Identifiable{
let id: Int
let name: String
var movies: [Movie]?
}
struct Movie: Codable, Hashable, Identifiable {
let title: String
let id: Int
let posterPath: String?
let backdropPath : String?
var tagline: String?
}
loadGenres() is AnyPublisher<[Genre], Error>
fetchMoviesIn() is AnyPublisher<[Movie], Error>
class GenresViewModel: ObservableObject{
@Published var genres = [Genre]()
@Published var movies = [Movie]()
var requests = Set<AnyCancellable>()
init(){
NetworkManager.shared.loadGenres()
.flatMap{ genres in
genres.publisher.flatMap{ genre in
NetworkManager.shared.fetchMoviesIn(genre)
}
}
.collect()
.retry(1)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
switch completion{
case .finished:
print("Finished loading all movies in every genre")
case .failure(let error):
print("Error: \(error)")
}
}, receiveValue: { [self] values in
let allMovies = values.joined()
self.movies = allMovies.map{$0}
})
.store(in: &self.requests)
}
}
Respuestas
Depende de cómo quieras recopilar géneros y películas.
Por ejemplo, ¿quieres un género y una lista de películas de ese género? El resultado podría ser una matriz de (Genre, [Movies])
.
NetworkManager.shared.loadGenres()
.flatMap { genres in
genres.publisher.setFailureType(to: Error.self)
}
.flatMap { genre in
NetworkManager.shared.fetchMoviesIn(genre)
.map { movies in (genre, movies) }
}
.collect()
O, si desea una variedad de (Genre, Movie)
tuplas, entonces es un enfoque similar, pero con un nivel adicional .flatMap
para obtener películas individuales.
NetworkManager.shared.loadGenres()
.flatMap { genres in
genres.publisher.setFailureType(to: Error.self)
}
.flatMap { genre in
NetworkManager.shared.fetchMoviesIn(genre)
.flatMap { movies in
movies.publisher.setFailureType(to: Error.self)
}
.map { movie in (genre, movie) }
}
.collect()
Para responder a la pregunta de su comentario, desea devolver la actualización Genre
, puede devolverla en lugar de devolver una tupla. Tenga en cuenta que, dado que Genre
es una estructura, deberá crear una copia variable del objeto (la genre
disponible en el flatMap
cierre es una constante), actualizar la copia y devolver eso:
NetworkManager.shared.loadGenres()
.flatMap { genres in
genres.publisher.setFailureType(to: Error.self)
}
.flatMap { genre in
NetworkManager.shared.fetchMoviesIn(genre)
.map { movies -> Genre in
var genreCopy = genre
genreCopy.movies = movies
return genreCopy
}
}
.collect()