Chaining swift รวมผู้เผยแพร่และรับผลลัพธ์แต่ละรายการ

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