我很难弄清楚如何从我的publisher 1循环TMDb结果,并将我从key id获得的值用于我的第二个publisher。它不会遍历每个结果,它会在我的func fetchVideos(_ id: Int)中获得正确的网址,但它不会从TMDb的结果数组中调用每个网址,我不确定是不是因为我还从Videos可编码数据中获得了一个结果数组?
我尝试在我的第一个发布者的flatMap中使用Publishers.MergeMany。对于combine,我仍然是一个新手,任何提示都会有帮助。我正在尝试获取电影列表,然后从电影中获取id密钥,然后使用它来获取每部电影的电影预告片数据。
打印输出
https://api.themoviedb.org/3/movie/602223/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/459151/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/385128/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/522478/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/637693/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/529203/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/578701/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/631843/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/645856/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/581644/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/436969/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/568620/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/522931/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/681260/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/630586/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/671/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/618416/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/646207/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/550988/videos?api_key=API_KEY&language=en-US
https://api.themoviedb.org/3/movie/482373/videos?api_key=API_KEY&language=en-US
Videos(id: 459151, results: [themoviedb_demo.Video(id: 3F24D610-4261-4AEB-8906-A9D0E5FE8E4D, iso639_1: "en", iso3166_1: "US", key: "CK6xdYIsaa0", name: "DreamWorks\' The Boss Baby: Family Business | Official Trailer #3 | Peacock", site: "YouTube", size: 1080, type: "Trailer"), themoviedb_demo.Video(id: 417EF49C-B983-4CC3-B435-7A902DECE917, iso639_1: "en", iso3166_1: "US", key: "-rF2j6K5FoM", name: "The Boss Baby 2: Family Business – Official Trailer 2 (Universal Pictures) HD", site: "YouTube", size: 1080, type: "Trailer"), themoviedb_demo.Video(id: C34A3F5F-9429-4267-86F0-5506EF3E8281, iso639_1: "en", iso3166_1: "US", key: "QPzy8Ckza08", name: "THE BOSS BABY: FAMILY BUSINESS | Official Trailer", site: "YouTube", size: 1080, type: "Trailer")])可编码数据
struct Videos: Codable {
let id: Int
let results: [Video]
}
struct Video: Codable {
let id = Int
let key: String
let name: String
enum CodingKeys: String, CodingKey {
case id
case key, name
}
}
struct TMDb: Codable {
let results: [Results]?
}
struct Results: Codable {
let id: Int
let releaseDate, title: String?
let name: String?
enum CodingKeys: String, CodingKey {
case id
case releaseDate = "release_date"
case title
case name
}
}@Published var movies = TMDb(results: Array(repeating: Results(id: 1, releaseDate: "", title: "", name: "") , count: 5))
@Published var videos = Videos(id: 1, results: Array(repeating: Video(id: 1, key: "", name: "") , count: 5))
func getUpcoming() {
var request = URLRequest(url:URL(string:"https://api.themoviedb.org/3/movie/upcoming?api_key=API_KEY&language=en-US&page=1")!)
request.httpMethod = "GET"
let publisher = URLSession.shared.dataTaskPublisher(for: request)
.map{ $0.data }
.decode(type: TMDb.self, decoder: JSONDecoder())
let publisher2 = publisher
.flatMap{
// loop results from TMDb for id for publisher 2, only one is called
Publishers.MergeMany($0.results!.map { item in
return self.fetchVideos(item.id)
.map { $0 as Videos }
.replaceError(with: nil)
})
}
// Publishers.CombineLatest
Publishers.Zip(publisher, publisher2)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: {_ in
}, receiveValue: { movies, videos in
self.movies = movies
self.videos = videos
}).store(in: &cancellables)
}
func fetchVideos(_ id: Int) -> AnyPublisher<Videos, Error> {
let url = URL(string: "https://api.themoviedb.org/3/movie/\(id)/videos?api_key=API_KEY&language=en-US")!
return URLSession.shared.dataTaskPublisher(for: url)
.mapError { $0 as Error }
.map{ $0.data }
.decode(type: Videos.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}发布于 2021-07-29 21:00:36
Hi @cole对于此操作,您不需要合并或压缩,因为您不是订阅两个发布者,而是在第一个发布者发出事件后尝试执行操作。
在我看来,你只需要一个地图.handleEvents就可以了。
因此,让我们尝试增强您的代码,我们希望分别更新电影和视频,但我们仍然需要视频依赖于电影
首先,我们将创建请求电影的发布者:
var request = URLRequest(url:URL(string:"https://api.themoviedb.org/3/movie/upcoming?api_key=API_KEY&language=en-US&page=1")!)
request.httpMethod = "GET"
let publisher = URLSession.shared.dataTaskPublisher(for: request)
.map{ $0.data }
.decode(type: TMDb.self, decoder: JSONDecoder())现在我们通过分配电影来增强这个发布者的处理:
var request = URLRequest(url:URL(string:"https://api.themoviedb.org/3/movie/upcoming?api_key=API_KEY&language=en-US&page=1")!)
request.httpMethod = "GET"
let publisher = URLSession.shared.dataTaskPublisher(for: request)
.map{ $0.data }
.decode(type: TMDb.self, decoder: JSONDecoder())
.sink(receiveCompletion: { print ($0) },
receiveValue: { self.movies = $0.results })现在我们将添加.handleEvent,以便遍历我们的电影,以创建所有发布视频事件并为视频数组追加视频的发布者:
var request = URLRequest(url:URL(string:"https://api.themoviedb.org/3/movie/upcoming?api_key=API_KEY&language=en-US&page=1")!)
request.httpMethod = "GET"
let publisher = URLSession.shared.dataTaskPublisher(for: request)
.map{ $0.data }
.decode(type: TMDb.self, decoder: JSONDecoder())
.sink(receiveCompletion: { print ($0) },
receiveValue: { self.movies = $0.results })
.handleEvents(receiveSubscription:nil, receiveOutput: { [weak self] movies in guard let self = self else {return}
self.videos = [Videos]()
for movie in movies.results {
self.fetchVideos(movie.id)
}, receiveCompletion:nil, receiveCancel:nil, receiveRequest:nil)
})
.store(in: &cancellables)现在,对于最后一步,让我们相应地更新fetchVideos:
func fetchVideos(_ id: Int) {
let url = URL(string: "https://api.themoviedb.org/3/movie/\(id)/videos?api_key=API_KEY&language=en-US")!
return URLSession.shared.dataTaskPublisher(for: url)
.mapError { $0 as Error }
.map{ $0.data }
.decode(type: Videos.self, decoder: JSONDecoder())
.sink(receiveCompletion: { print ($0) },
receiveValue: { [weak self] videos in guard let self = self else {return}
self.videos.append(videos)
})
.store(in: &cancellables)
}发布于 2021-07-29 20:51:49
解决了我自己的问题。我需要为我的@Published变量创建一个数组,而不是单个项目。然后,我需要在我的发布者的flatMap中调用.collect()和.append(),它将附加到我的@Published变量videos中。

https://stackoverflow.com/questions/68581162
复制相似问题