结合:如何取消平面地图的发布者
Combine: How to cancel a flatMap'ed publisher
这里是 Combine 和反应式编程的新手,非常感谢您的帮助。
我有以下情况:我想构建一个 UI,用户可以在其中通过页面上的各种 'filter' 按钮过滤内容。当用户点击其中一个按钮时,我需要发出 API 请求以获取数据。
现在,我有一个发布商为我提供 'state' 这些选择,我的代码结构如下:
state
.publisher /* sends whenever 'state' updates behind the scenes */
.debounce(for: 1.0, scheduler: DispatchQueue.main)
.map { /* create some URL request */ }
.flatMap {
URLSession.shared.dataTaskPublisher(for: someRequest)
.map { [=10=].data }
.decode(type: MyResponseType.self, decoder: JSONDecoder())
}.sink(receiveCompletion: { (completion) in
/// cancelled
}) { (output) in
/// go show my results
/// Ideally, this is only called when the most recent API call finishes!
}.store(in: &cancellables)
但是,此实现在以下情况下存在错误:如果一个事件通过 flatMap 触发请求,而后续事件在网络调用完成之前执行相同的操作,那么我们将调用两次完成处理程序。
最好,我们以某种方式取消内部管道,因此我们只使用最近的事件执行完成处理程序。
当新事件通过管道传输时,如何在不拆除外部管道的情况下'cancel'内部管道(由 dataTaskPublisher 启动的管道)?
你不想要 flatMap
。你想要switchToLatest
。将您的 flatMap
更改为普通的 map
,然后在其后添加 .switchToLatest()
。因为 switchToLatest
要求故障类型匹配,所以您可能还需要使用 mapError
。 decode
运算符产生失败类型 Error
,因此您可以 mapError
到 Error
.
示例:
state
.publisher /* sends whenever 'state' updates behind the scenes */
.debounce(for: 1.0, scheduler: DispatchQueue.main)
.map { makeURLRequest(from: [=10=]) }
.map({ someRequest in
URLSession.shared.dataTaskPublisher(for: someRequest)
.map { [=10=].data }
.decode(type: MyResponseType.self, decoder: JSONDecoder())
})
.mapError { [=10=] as Error }
.switchToLatest()
.sink(
receiveCompletion: ({ (completion) in
print(completion)
/// cancelled
}),
receiveValue: ({ (output) in
print(output)
/// go show my results
/// Ideally, this is only called when the most recent API call finishes!
}))
.store(in: &cancellables)
这里是 Combine 和反应式编程的新手,非常感谢您的帮助。
我有以下情况:我想构建一个 UI,用户可以在其中通过页面上的各种 'filter' 按钮过滤内容。当用户点击其中一个按钮时,我需要发出 API 请求以获取数据。
现在,我有一个发布商为我提供 'state' 这些选择,我的代码结构如下:
state
.publisher /* sends whenever 'state' updates behind the scenes */
.debounce(for: 1.0, scheduler: DispatchQueue.main)
.map { /* create some URL request */ }
.flatMap {
URLSession.shared.dataTaskPublisher(for: someRequest)
.map { [=10=].data }
.decode(type: MyResponseType.self, decoder: JSONDecoder())
}.sink(receiveCompletion: { (completion) in
/// cancelled
}) { (output) in
/// go show my results
/// Ideally, this is only called when the most recent API call finishes!
}.store(in: &cancellables)
但是,此实现在以下情况下存在错误:如果一个事件通过 flatMap 触发请求,而后续事件在网络调用完成之前执行相同的操作,那么我们将调用两次完成处理程序。
最好,我们以某种方式取消内部管道,因此我们只使用最近的事件执行完成处理程序。
当新事件通过管道传输时,如何在不拆除外部管道的情况下'cancel'内部管道(由 dataTaskPublisher 启动的管道)?
你不想要 flatMap
。你想要switchToLatest
。将您的 flatMap
更改为普通的 map
,然后在其后添加 .switchToLatest()
。因为 switchToLatest
要求故障类型匹配,所以您可能还需要使用 mapError
。 decode
运算符产生失败类型 Error
,因此您可以 mapError
到 Error
.
示例:
state
.publisher /* sends whenever 'state' updates behind the scenes */
.debounce(for: 1.0, scheduler: DispatchQueue.main)
.map { makeURLRequest(from: [=10=]) }
.map({ someRequest in
URLSession.shared.dataTaskPublisher(for: someRequest)
.map { [=10=].data }
.decode(type: MyResponseType.self, decoder: JSONDecoder())
})
.mapError { [=10=] as Error }
.switchToLatest()
.sink(
receiveCompletion: ({ (completion) in
print(completion)
/// cancelled
}),
receiveValue: ({ (output) in
print(output)
/// go show my results
/// Ideally, this is only called when the most recent API call finishes!
}))
.store(in: &cancellables)