结合框架序列化异步操作 [英] Combine framework serialize async operations

查看:61
本文介绍了结合框架序列化异步操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使构成Combine框架的异步管道同步(串行)排列?

How do I get the asynchronous pipelines that constitute the Combine framework to line up synchronously (serially)?

假设我有50个URL,我想从中下载相应的资源,假设我想一次做到这一点.我知道如何使用Operation/OperationQueue做到这一点,例如使用在下载完成之前不会声明自身完成的Operation子类.我如何使用Combine来做同样的事情?

Suppose I have 50 URLs from which I want to download the corresponding resources, and let's say I want to do it one at a time. I know how to do that with Operation / OperationQueue, e.g. using an Operation subclass that doesn't declare itself finished until the download is complete. How would I do the same thing using Combine?

此刻,我要做的是保留剩余URL的全局列表并弹出一个列表,为一个下载设置一个管道,进行下载,然后在管道的sink中重复.看起来不太像Combine.

At the moment all that occurs to me is to keep a global list of the remaining URLs and pop one off, set up that one pipeline for one download, do the download, and in the sink of the pipeline, repeat. That doesn't seem very Combine-like.

我确实尝试制作一个URL数组并将其映射到一个发布者数组.我知道我可以产生"一个发布者,并使用flatMap使它在管道中发布.但是我仍然同时进行所有下载.没有任何Combine方法以受控方式遍历数组-还是有?

I did try making an array of the URLs and map it to an array of publishers. I know I can "produce" a publisher and cause it to publish on down the pipeline using flatMap. But then I'm still doing all the downloading simultaneously. There isn't any Combine way to walk the array in a controlled manner — or is there?

(我也曾想过与Future一起做些事情,但是我变得无望地感到困惑.我不习惯这种思维方式.)

(I also imagined doing something with Future but I became hopelessly confused. I'm not used to this way of thinking.)

推荐答案

我仅对此进行了简短的测试,但是在初次通过时,似乎每个请求在开始之前都等待上一个请求完成.

I've only briefly tested this, but at first pass it appears that each request waits for the previous request to finish before starting.

我正在发布此解决方案以寻求反馈.如果这不是一个好的解决方案,请务必加以批评.

I'm posting this solution in search of feedback. Please be critical if this isn't a good solution.

extension Collection where Element: Publisher {

    func serialize() -> AnyPublisher<Element.Output, Element.Failure>? {
        // If the collection is empty, we can't just create an arbititary publisher
        // so we return nil to indicate that we had nothing to serialize.
        if isEmpty { return nil }

        // We know at this point that it's safe to grab the first publisher.
        let first = self.first!

        // If there was only a single publisher then we can just return it.
        if count == 1 { return first.eraseToAnyPublisher() }

        // We're going to build up the output starting with the first publisher.
        var output = first.eraseToAnyPublisher()

        // We iterate over the rest of the publishers (skipping over the first.)
        for publisher in self.dropFirst() {
            // We build up the output by appending the next publisher.
            output = output.append(publisher).eraseToAnyPublisher()
        }

        return output
    }
}


此解决方案的更简洁版本(由@matt提供):


A more concise version of this solution (provided by @matt):

extension Collection where Element: Publisher {
    func serialize() -> AnyPublisher<Element.Output, Element.Failure>? {
        guard let start = self.first else { return nil }
        return self.dropFirst().reduce(start.eraseToAnyPublisher()) {
            $0.append($1).eraseToAnyPublisher()
        }
    }
}

这篇关于结合框架序列化异步操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆