gpt4 book ai didi

ios - 组合框架 : how to process each element of array asynchronously before proceeding

转载 作者:行者123 更新时间:2023-12-01 10:17:38 28 4
gpt4 key购买 nike

我在使用 iOS Combine 框架时遇到了一些心理障碍。

我正在将一些代码从“手动”从远程 API 获取转换为使用组合。基本上,API 是 SQL 和 REST(实际上是 Salesforce,但这与问题无关)。代码用来做的是调用一个接受完成处理程序的 REST 查询方法。我正在做的是用结合 future 替换它无处不在。到现在为止还挺好。

当以下场景发生时,问题就出现了(并且经常发生):

  • 我们执行 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 { ... }
    partialObject.property1 = // something from partialObjects2
    partialObject.property2 = // something from partialObjects2
    // and we could go down yet _another_ level in some cases
    }
    }
    group.notify {
    completion([partialObjects])
    }
    }
    }

    每次说 results in在伪代码中,这是异步网络调用的完成处理程序。

    好吧,我很清楚如何在Combine 中链接异步调用,例如通过使用Futures 和 flatMap (再次伪代码):
    let future1 = Future...
    future1.map {
    // do something
    }.flatMap {
    let future2 = Future...
    return future2.map {
    // do something
    }
    }
    // ...

    在该代码中,我们形成 future2 的方式可以取决于我们从 future1 的执行中收到的值,并在 mapfuture2我们可以修改从上游收到的内容,然后再将其传递到管道中。没问题。这一切都非常漂亮。

    但这并没有给我我在组合前代码中所做的事情,即循环。在这里,我在一个循环中执行多个异步调用,在继续之前由 DispatchGroup 保持在适当的位置。问题是:

    这样做的组合模式是什么?

    记住情况。我有一些对象的数组。我想遍历该数组,对循环中的每个对象进行异步调用,异步获取新信息并在此基础上修改该对象,然后再继续执行管道。每个循环可能涉及进一步的嵌套循环,以异步方式收集更多信息:
    Fetch info from online database, it's an array
    |
    V
    For each element in the array, fetch _more_ info, _that's_ an array
    |
    V
    For each element in _that_ array, fetch _more_ info
    |
    V
    Loop thru the accumulated info and populate that element of the original array

    执行此操作的旧代码看起来很糟糕,充满嵌套的完成处理程序和由 DispatchGroup 保持的循环 enter/ leave/ notify .但它奏效了。我无法让我的组合代码以同样的方式工作。我该怎么做?基本上我的管道输出是一个数组,我觉得我需要将该数组拆分为单个元素,对每个元素异步执行某些操作,然后将这些元素重新组合成一个数组。如何?

    我一直在解决这个问题的方法有效,但不能扩展,特别是当异步调用需要到达管道链中几步后的信息时。我一直在做这样的事情(我从 https://stackoverflow.com/a/58708381/341994 得到这个想法):
  • 一组对象从上游到达。
  • 我输入一个 flatMapmap数组到一个发布者数组,每个发布者都由一个 Future 领导,该 Future 获取与一个对象相关的更多在线内容,然后是一个生成修改后对象的管道。
  • 现在我有一系列管道,每个管道产生一个对象。我merge该数组并从 flatMap 生成该发布者(MergeMany) .
  • collect结果值返回到一个数组中。

  • 但这似乎仍然需要大量工作,更糟糕的是,当每个子管道本身需要生成一系列子管道时,它无法扩展。这一切都变得难以理解,过去很容易到达完成块的信息(因为 Swift 的范围规则)不再到达主管道中的后续步骤(或者很难到达,因为我在管道中传递越来越大的元组)。

    必须有一些简单的组合模式才能做到这一点,但我完全错过了它。请告诉我它是什么。

    最佳答案

    使用您的最新编辑和以下评论:

    I literally am asking is there a Combine equivalent of "don't proceed to the next step until this step, involving multiple asynchronous steps, has finished"


    我认为这种模式可以通过 .flatMap 实现到一个数组发布者 (Publishers.Sequence),它一个一个地发出并完成,然后是任何需要的每元素异步处理,并以 .collect 结束。 , 在继续之前等待所有元素完成
    所以,在代码中,假设我们有这些函数:
    func getFoos() -> AnyPublisher<[Foo], Error>
    func getPartials(for: Foo) -> AnyPublisher<[Partial], Error>
    func getMoreInfo(for: Partial, of: Foo) -> AnyPublisher<MoreInfo, Error>
    我们可以执行以下操作:
    getFoos()
    .flatMap { fooArr in
    fooArr.publisher.setFailureType(to: Error.self)
    }

    // per-foo element async processing
    .flatMap { foo in

    getPartials(for: foo)
    .flatMap { partialArr in
    partialArr.publisher.setFailureType(to: Error.self)
    }

    // per-partial of foo async processing
    .flatMap { partial in

    getMoreInfo(for: partial, of: foo)
    // build completed partial with more info
    .map { moreInfo in
    var newPartial = partial
    newPartial.moreInfo = moreInfo
    return newPartial
    }
    }
    .collect()
    // build completed foo with all partials
    .map { partialArr in
    var newFoo = foo
    newFoo.partials = partialArr
    return newFoo
    }
    }
    .collect()
    (删除旧答案)

    关于ios - 组合框架 : how to process each element of array asynchronously before proceeding,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61841254/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com