如何在Swift中使用AsyncStream创建类似回调的行为
hudson 译 原文
毫无疑问,Swift并发彻底改变了我们在Swift中处理异步代码的方式。它的一个强大组件是AsyncStream
,这是一种特殊的AsyncSequence
形式,非常适合使用async/await 语法实现回调或类似委托的行为。
在Swift 并发之前,开发人员必须依靠闭包来触发回调,并在异步操作期间通知调用者某些事件。然而,随着AsyncStream
的引入,这种基于闭包的方法现在可以被更直观、更直接的async/await语法所取代。
在本文中,让我们探索一个简单而说明性的示例,说明如何利用AsyncStream
来跟踪下载操作的进度。阅读完成后,您将很好地了解AsyncStream
的工作原理,并开始在自己的项目中使用它。
所以,不用多说,让我们开始吧。
示例应用程序
为了展示AsyncStream
的力量,让我们创建一个示例应用程序,该应用程序将模拟下载操作,并使用进度条显示下载进度。
为了模拟通常与文件下载相关的等待期,我创建了一个带有 performDownload()
方法的File
结构,该方法将随机睡眠一段时间。
1 | swift复制代码struct File { |
在现实生活中,这种performDownload()
方法很可能由连接到服务器并等待其响应的代码组成。
有了这个解释,让我们深入研究有趣的部分。
创建异步流
首先,让我们创建一个下载器类(FileDownloader
),该类接受File
文件对象数组并逐个下载,每次成功下载后,它将通过提供下载文件的文件名来通知调用者。
为了实现这种行为,基于闭包的方法很可能看起来像这样:
1 | swift复制代码static func download(_ files: [File], completion: (String) -> Void) { |
然而,如果我们选择async/await语法,我们将需要用AsyncStream
替换完成处理程序。
1 | swift复制代码static func download(_ files: [File]) -> AsyncStream<String> { |
如上述代码所示,我们可以通过给它一个元素类型和自定义闭包来初始化AsyncStream
,该闭包将元素交给AsyncStream
。在我们的案例中,我们将元素类型设置为String
,因为每次下载成功时,我们的闭包将产生下载文件的文件名。
有了这些,我们可以像这样实现执行下载操作的自定义闭包:
1 | swift复制代码// Init AsyncStream with element type = `String` |
使用AsyncStream
时要记住的一个要点是在完成所有操作后调用延续的finish()
方法。这一步骤至关重要,因为如果不这样做,将导致在调用点无限期等待,导致我们应用程序中的意外和非预期的行为。
消费AsyncStream
有了FileDownloader
,是时候将其与用户界面集成以显示下载进度了。首先,我们将创建50个File
对象并触发下载过程。
1 | swift复制代码let totalFile = 50 |
现在,为了在UI上显示下载进度,我们将利用给定的AsyncStream
实例(downloaderStream
),并利用for-wait-in
语法处理每个文件名,文件名是在调用延续的yield()
方法时由 AsyncStream
生成的。
1 | swift复制代码Task { |
如前所述,调用延续的 finish()
方法是一个必不可少的步骤。如果没有此步骤,for循环将无限期等待,状态消息将不会更改为“下载完成”。
如果您想亲自尝试一下,您可以在GitHub上找到完整的示例代码。
感谢您的阅读。👨🏻💻
本文转载自: 掘金