如何在地图后使用 Combine collect 方法

How to use Combine collect method after a map

我想使用 Combine 的 collect 方法将对象数组拆分为多个数组的数组,这些数组将对应于集合视图中的行(例如:[Item, Item, Item, Item, Item] 将变为 [[Item, Item, Item], [Item, Item]] 等等)

我的数据来自两个发布者,我正在链接它们以将我的数据合并到我的视图使用的单一类型中。

这是我的代码:

APIClient().send(APIEndpoints.searchMovies(for: text)).flatMap { response -> AnyPublisher<APIResponseList<TVShow>, Error> in
            movies = response.results.map { SearchItemViewModel(movie: [=10=])}
            return APIClient().send(APIEndpoints.searchTVShows(for: text))
        }
        .map { response -> [SearchItemViewModel] in
            tvShows = response.results.map { SearchItemViewModel(tvShow: [=10=])}
            let concatItems = tvShows + movies
            return concatItems.sorted { [=10=].popularity > .popularity }
        }
        .collect(3)
        .sink(receiveCompletion: { (completion) in
            switch completion {
            case .failure:
                self.state = .error
                self.items = []
            case .finished:
                break
            }
        }, receiveValue: { (response) in
            self.state = .data
            self.items = response
        })
            .store(in: &disposables)

我目前的问题是,在我的 sink receiveValue 闭包中, response 参数不等于预期结果,它只是将我所有的项目分组到一个数组中,就像这样: [Item, Item, Item, Item, Item] -> [[Item, Item, Item, Item, Item]] collect 方法似乎没有按预期工作,知道如何解决这个问题吗?

创建此扩展:

extension Array {
    func split(numItems:Int) -> [[Element]] {
        var i = 0
        var ret = [[Element]]()
        var current = [Element]()
        while i < self.count {
            current.append(self[i])
            i += 1
            if i % numItems == 0 {
                ret.append(current)
                current = []
            }
        }
        if current.count > 0 {
            ret.append(current)
        }
        return ret
    }
}

现在,您应该可以这样做了:

APIClient().send(APIEndpoints.searchMovies(for: text)).flatMap { response -> AnyPublisher<APIResponseList<TVShow>, Error> in
            movies = response.results.map { SearchItemViewModel(movie: [=11=])}
            return APIClient().send(APIEndpoints.searchTVShows(for: text))
        }
        .map { response -> [SearchItemViewModel] in
            tvShows = response.results.map { SearchItemViewModel(tvShow: [=11=])}
            let concatItems = tvShows + movies
            var sorted =  concatItems.sorted { [=11=].popularity > .popularity }
            return sorted.split(numItems:3)
        }
        .sink(receiveCompletion: { (completion) in
            switch completion {
            case .failure:
                self.state = .error
                self.items = []
            case .finished:
                break
            }
        }, receiveValue: { (response) in
            self.state = .data
            self.items = response
        })
            .store(in: &disposables)

it just group all my items into an array like this : [Item, Item, Item, Item, Item]

通过 flatMap 传递并生成其序列发布者。现在 Item 对象将一次到达一个,并且 collect(3) 将按您预期的那样工作。

示例:

var storage = Set<AnyCancellable>()
let head = Just([1,2,3,4,5]) // this is the same as your `.map`
head
    .flatMap { [=10=].publisher }
    .collect(3)
    .sink{print([=10=])} // prove that it works: [1, 2, 3], then [4, 5]
    .store(in: &storage)