使用 Swift 并发 URLSession API 下载文件

了解如何使用 iOS 15 引入的全新基于并发的 URLSession 方法,在 SwiftUI 应用中获取和存储远程数据。

使用 Swift 并发 URLSession API 下载文件

在 iOS 15 及之后的系统中,URLSession 扩展了 Swift Concurrency 功能,新增了一系列 async/await 风格的网络请求方法,用简单优雅的 async/await 语法取代了繁琐的回调模式,使代码更加可读和易于维护。

新的 API 包括:

  • data(for:delegate:)
  • download(for:delegate:)
  • upload(for:from:delegate:)

新的 API 简介

data(for:delegate:)

发起一般的网络请求,拿回响应的 Data 和 URLResponse。常用于请求 JSON、XML、或其他格式的文本、二进制数据,拿到后做进一步解析。

适用场合

  • 适合小或中等体量的数据传输:比如 JSON 响应、图片、文本、二进制文件等。
  • 需要一次性将所有数据加载到内存 的场景:例如解析 JSON 或用 UIImage(data:) 直接创建图片。

download(for:delegate:)

下载大文件、视频、音频等,将其直接存储到临时文件而非内存中。

适用场合

  • 下载大文件:因为它无需把整个文件都加载进内存,而是直接写到临时文件。
  • 视频/音频/压缩包 等较大体量资源。
  • 想要在后台下载 或希望可以进行断点续传(URLSessionDownloadDelegate)。

upload(for:from:delegate:)

实现大文件或表单数据的上传,并将其转换成并发友好的 async/await 流程。和 data(for:) 类似,但侧重点是把本地文件或数据上传到服务器。

适用场合

  • 上传表单、图像、视频 等需要较大带宽的上传任务。
  • 后台上传:同样可以通过设置自定义的 URLSession(configuration:delegate:delegateQueue:) 来支持后台上传和进度监听。

URLSession.shared.download(for:delegate:) 

这个 API 的核心是 download(for:) 方法,它返回一个元组 (URL, URLResponse)。元组的,

  • 第一个元素表示下载数据的本地文件位置
  • 第二个元素是 URL 响应

处理下载

以下是在异步上下文中构建下载函数的示例:

func downloadFile(from url: URL) async throws -> URL {
    // 1. 从 URL 创建请求
    let request = URLRequest(url: url)
    
    // 2. 使用 Swift 并发执行下载
    let (fileURL, response) = try await URLSession.shared.download(for: request)
    
    // 3. (可选)如果需要,验证响应
    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw URLError(.badServerResponse)
    }
    
    // 4. 返回临时文件 URL(您可以将其移动到永久位置)
    return fileURL
}

方法参数

  1. URLRequest: 定义要下载的远程资源的请求。
  2. URL: 下载资源的临时文件 URL。
  3. URLResponse: 包含响应的元数据,例如状态码和头信息。

需要将文件从临时位置移动或复制到更持久的目录。

显示下载进度

该方法目前未提供直接获取下载进度信息的能力。

保存文件到本地