如何展平 AnyPublisher<AnyPublisher<>>?
How Can I Flatten An AnyPublisher<AnyPublisher<>>?
我从 RESTful 服务器加载端点,其中一些是多页的。它们由 header 响应中的 'x-pages' 字段表示。我想创建一个发布者,它将 return 来自所有页面的所有 objects 作为一个数组。
最后一个 return 语句存在编译错误。
Cannot convert return expression of type 'AnyPublisher<AnyPublisher<[T], LoadingError>, LoadingError>\' to return type 'AnyPublisher<[T], LoadingError>'
如何修复此 "embedded" 发布者?
import Combine
import Foundation
enum LoadingError: Error {
case url(URLError)
case decode(Error)
case couldNotDetermieLastPageNumber(URL)
}
func multipageDataTaskPublishter<T>(for endpoint: Endpoint) -> AnyPublisher<[T], LoadingError> where T: Decodable {
assert(endpoint.page == 1)
let publisher = URLSession.shared.dataTaskPublisher(for: endpoint.url)
.retry(1)
.mapError { LoadingError.url([=12=]) }
.map { (arg) -> AnyPublisher<[T], LoadingError> in
let (_, response) = arg
guard
let header = response as? HTTPURLResponse,
let xpages = header.value(forHTTPHeaderField: "x-pages"),
let lastPage = Int(xpages)
else {
return Fail(error: LoadingError.couldNotDetermieLastPageNumber(endpoint.url))
.eraseToAnyPublisher()
}
let publishers = (1...lastPage).map { page -> AnyPublisher<[T], LoadingError> in
let next = endpoint.for(page: page)
return URLSession.shared.dataTaskPublisher(for: next.url)
.retry(1)
.mapError { LoadingError.url([=12=]) }
.map { [=12=].data }
.decode(type: [T].self, decoder: JSONDecoder())
.mapError { LoadingError.decode([=12=]) }
.eraseToAnyPublisher()
}
return Publishers.Sequence(sequence: publishers)
.flatMap { [=12=] }
.reduce([], +)
.eraseToAnyPublisher()
}
return publisher.eraseToAnyPublisher()
}
我可以在创建多页发布者时在守卫之后立即添加一个接收器来读取最后一页值。然后将 let publishers = ...
部分从地图中提升一层,我的 Publishers.Sequence return 值将是正确的。但这在很多层面上似乎都是错误的;拆分执行,不可组合。
此外,我发现我的实现加载了第一页两次。稍后拆分管道并合并数据有效负载会更好,我想找到那个解决方案,但我需要先解决这个问题。如果这是一个无望的原因,那么就这样吧,任何惯用的 Combine 解决方案都将被接受。
这一行 .map { (arg) -> AnyPublisher<[T], LoadingError> in
需要是 flatMap
。
我从 RESTful 服务器加载端点,其中一些是多页的。它们由 header 响应中的 'x-pages' 字段表示。我想创建一个发布者,它将 return 来自所有页面的所有 objects 作为一个数组。
最后一个 return 语句存在编译错误。
Cannot convert return expression of type 'AnyPublisher<AnyPublisher<[T], LoadingError>, LoadingError>\' to return type 'AnyPublisher<[T], LoadingError>'
如何修复此 "embedded" 发布者?
import Combine
import Foundation
enum LoadingError: Error {
case url(URLError)
case decode(Error)
case couldNotDetermieLastPageNumber(URL)
}
func multipageDataTaskPublishter<T>(for endpoint: Endpoint) -> AnyPublisher<[T], LoadingError> where T: Decodable {
assert(endpoint.page == 1)
let publisher = URLSession.shared.dataTaskPublisher(for: endpoint.url)
.retry(1)
.mapError { LoadingError.url([=12=]) }
.map { (arg) -> AnyPublisher<[T], LoadingError> in
let (_, response) = arg
guard
let header = response as? HTTPURLResponse,
let xpages = header.value(forHTTPHeaderField: "x-pages"),
let lastPage = Int(xpages)
else {
return Fail(error: LoadingError.couldNotDetermieLastPageNumber(endpoint.url))
.eraseToAnyPublisher()
}
let publishers = (1...lastPage).map { page -> AnyPublisher<[T], LoadingError> in
let next = endpoint.for(page: page)
return URLSession.shared.dataTaskPublisher(for: next.url)
.retry(1)
.mapError { LoadingError.url([=12=]) }
.map { [=12=].data }
.decode(type: [T].self, decoder: JSONDecoder())
.mapError { LoadingError.decode([=12=]) }
.eraseToAnyPublisher()
}
return Publishers.Sequence(sequence: publishers)
.flatMap { [=12=] }
.reduce([], +)
.eraseToAnyPublisher()
}
return publisher.eraseToAnyPublisher()
}
我可以在创建多页发布者时在守卫之后立即添加一个接收器来读取最后一页值。然后将 let publishers = ...
部分从地图中提升一层,我的 Publishers.Sequence return 值将是正确的。但这在很多层面上似乎都是错误的;拆分执行,不可组合。
此外,我发现我的实现加载了第一页两次。稍后拆分管道并合并数据有效负载会更好,我想找到那个解决方案,但我需要先解决这个问题。如果这是一个无望的原因,那么就这样吧,任何惯用的 Combine 解决方案都将被接受。
这一行 .map { (arg) -> AnyPublisher<[T], LoadingError> in
需要是 flatMap
。