如何让构成Combine框架的异步管道同步(串行)排队?
假设我有 50 个 URL,我想从中下载相应的资源,假设我想一次下载一个。我知道如何使用 Operation/OperationQueue 来做到这一点,例如使用一个 Operation 子类,该子类在下载完成之前不会声明自己已完成。我将如何使用Combine 做同样的事情?
目前我想到的只是保留一个剩余 URL 的全局列表并弹出一个,为一次下载设置一个管道,进行下载,然后在sink管道中重复。这似乎不太像结合。
我确实尝试制作一组 URL 并将其映射到一组发布者。我知道我可以“生产”一个发布者,并使用flatMap. 但后来我仍然在同时进行所有下载。没有任何组合方式以受控方式遍历阵列——或者有吗?
(我也想象过用 Future 做点什么,但我变得绝望了。我不习惯这种思维方式。)
我在使用 iOS Combine 框架时遇到了一些心理障碍。
我正在将一些代码从“手动”从远程 API 获取转换为使用组合。基本上,API 是 SQL 和 REST(实际上是 Salesforce,但这与问题无关)。代码用来做的是调用一个接受完成处理程序的 REST 查询方法。我正在做的是用结合未来到处替换它。到现在为止还挺好。
当以下场景发生时,问题就出现了(并且经常发生):
我们执行 REST 查询并返回一组“对象”。
但是这些“对象”并没有完全填充。它们中的每一个都需要来自某个相关对象的附加数据。因此,对于每个“对象”,我们使用来自该“对象”的信息进行另一个 REST 查询,从而为我们提供另一个“对象”数组。
这可能允许也可能不允许我们完成第一个“对象”的填充——否则,我们可能必须使用来自第二个“对象”中的每个“对象”的信息进行另一个REST 查询,依此类推。
结果是很多这样结构的代码(这是伪代码):
func fetchObjects(completion: @escaping ([Object] -> Void) {
let restQuery = ...
RESTClient.performQuery(restQuery) { results in
let partialObjects = results.map { ... }
let group = DispatchGroup()
for partialObject in partialObjects {
let restQuery = ... // something based on partialObject
group.enter()
RESTClient.performQuery(restQuery) { results in
group.leave()
let partialObjects2 = results.map …Run Code Online (Sandbox Code Playgroud) 我在一个项目中成功地使用了 PromiseKit,直到 Xcode 11 beta 破坏了 PK v7。为了减少外部依赖,我决定废弃 PromiseKit。处理链式异步代码的最佳替代品似乎是使用新组合框架的 Futures。
我正在努力使用 Combine 复制简单的 PK 语法
前任。简单的 PromiseKit 链式异步调用语法
getAccessCodeFromSyncProvider.then{accessCode in startSync(accessCode)}.then{popToRootViewController}.catch{handleError(error)}
Run Code Online (Sandbox Code Playgroud)
我明白:
async/await 的 Swift 标准库实现将解决这个问题(async/await 尚不存在,尽管Chris Latter 本人有很多喋喋不休和参与)
我可以使用信号量进行复制(容易出错?)
flatMap 可用于链接 Futures
我想要的异步代码应该能够按需调用,因为它涉及确保用户登录。我正在努力解决两个概念性问题。
如果我将 Futures 包装在一个方法中,sink以处理结果,则该方法似乎在订阅者被调用之前超出了范围sink。
由于 Futures 只执行一次,我担心如果我多次调用该方法,我只会从第一次调用中得到旧的、陈旧的结果。要解决这个问题,也许我会使用 PassthroughSubject?这允许按需调用发布者。
问题:
//how is this done using Combine?
func startSync() {
getAccessCodeFromSyncProvider.then{accessCode in startSync(accessCode)}.catch{\\handle error here}
}
Run Code Online (Sandbox Code Playgroud)