首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用flatMap链接

使用flatMap链接
EN

Stack Overflow用户
提问于 2021-07-29 18:22:22
回答 2查看 70关注 0票数 0

我很难弄清楚如何从我的publisher 1循环TMDb结果,并将我从key id获得的值用于我的第二个publisher。它不会遍历每个结果,它会在我的func fetchVideos(_ id: Int)中获得正确的网址,但它不会从TMDb的结果数组中调用每个网址,我不确定是不是因为我还从Videos可编码数据中获得了一个结果数组?

我尝试在我的第一个发布者的flatMap中使用Publishers.MergeMany。对于combine,我仍然是一个新手,任何提示都会有帮助。我正在尝试获取电影列表,然后从电影中获取id密钥,然后使用它来获取每部电影的电影预告片数据。

打印输出

代码语言:javascript
复制
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")])

可编码数据

代码语言:javascript
复制
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
    }
}
代码语言:javascript
复制
@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()
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-29 21:00:36

Hi @cole对于此操作,您不需要合并或压缩,因为您不是订阅两个发布者,而是在第一个发布者发出事件后尝试执行操作。

在我看来,你只需要一个地图.handleEvents就可以了。

因此,让我们尝试增强您的代码,我们希望分别更新电影和视频,但我们仍然需要视频依赖于电影

首先,我们将创建请求电影的发布者:

代码语言:javascript
复制
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())

现在我们通过分配电影来增强这个发布者的处理:

代码语言:javascript
复制
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,以便遍历我们的电影,以创建所有发布视频事件并为视频数组追加视频的发布者:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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)
 }
票数 2
EN

Stack Overflow用户

发布于 2021-07-29 20:51:49

解决了我自己的问题。我需要为我的@Published变量创建一个数组,而不是单个项目。然后,我需要在我的发布者的flatMap中调用.collect().append(),它将附加到我的@Published变量videos中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68581162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档