चेंजिंग स्विफ्ट प्रकाशकों को जोड़ती है और प्रत्येक परिणाम प्राप्त करती है

Aug 18 2020

नीचे दिए गए उदाहरण में, मैं विभिन्न मूवी शैलियों को लोड करने के लिए नेटवर्क अनुरोध कर रहा हूं, फिर सभी फिल्मों को लोड करने के लिए। सिंक केवल फिल्म परिणाम देता है। मैं दोनों शैलियों और फिल्मों को कैसे प्राप्त कर सकता हूं?

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)
    }
}

जवाब

2 NewDev Aug 18 2020 at 17:03

निर्भर करता है कि आप शैलियों और फिल्मों को कैसे इकट्ठा करना चाहते हैं।

उदाहरण के लिए, क्या आप उस शैली में एक शैली और फिल्मों की सूची चाहते हैं? परिणाम की एक सरणी हो सकती है (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()

या, यदि आप (Genre, Movie)टुपल्स की एक सरणी चाहते हैं , तो यह एक समान दृष्टिकोण है, लेकिन .flatMapव्यक्तिगत फिल्में प्राप्त करने के लिए एक अतिरिक्त स्तर के साथ

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()

आपके टिप्पणी के सवाल का जवाब देने के लिए, आप अपडेट लौटना चाहते हैं Genre, आप एक टपल वापस करने के बजाय वापस लौट सकते हैं। ध्यान रखें कि चूंकि Genreएक संरचना है, आपको ऑब्जेक्ट की एक वैरिएबल कॉपी बनाने की आवश्यकता होगी ( क्लोजर genreमें उपलब्ध flatMapएक स्थिर है), कॉपी को अपडेट करें, और उसे वापस करें:

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()