0Pricing
Swift Academy · 课时

重试逻辑与后台 URLSession

实现指数退避,并在后台继续下载。

重试逻辑与后台 URLSession 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

为什么要重试?

瞬时性失败(超时、503 服务不可用)是可以恢复的。重试逻辑无需用户干预即可提高应用的恢复能力。

func fetch(retries: Int = 3) async throws -> Data {
  for attempt in 0..<retries {
    do {
      return try await URLSession.shared.data(from: url).0
    } catch {
      if attempt == retries - 1 { throw error }
    }
  }
  fatalError("unreachable")
}

指数退避

逐渐延长重试之间的等待时间,以免给处于压力中的服务器造成过大负担:1 秒、2 秒、4 秒。

for attempt in 0..<maxRetries {
  do { return try await fetch() } catch {
    if attempt < maxRetries - 1 {
      try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(attempt))) * 1_000_000_000)
    } else { throw error }
  }
}

使用抖动避免惊群

在退避延迟中加入随机抖动,使重试的客户端不会在同一时刻全部访问服务器。

let baseDelay = pow(2.0, Double(attempt))
let jitter = Double.random(in: 0..<1)
let delay = (baseDelay + jitter) * 1_000_000_000
try await Task.sleep(nanoseconds: UInt64(delay))

可重试与不可重试的错误

只重试瞬时性错误。客户端错误(401、400)不应重试。

func isRetryable(_ error: Error) -> Bool {
  if let urlErr = error as? URLError {
    return urlErr.code == .timedOut || urlErr.code == .networkConnectionLost
  }
  if let netErr = error as? NetworkError, case .httpError(let code) = netErr {
    return code >= 500
  }
  return false
}

后台 URLSession

即使应用被挂起或终止,后台会话仍会继续下载。

let config = URLSessionConfiguration.background(withIdentifier: "com.myapp.background")
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)

用于后台任务的 URLSessionDelegate

实现 URLSessionDelegate,以便应用在后台任务完成后重新启动时接收完成回调。

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
  let dest = documentsURL.appendingPathComponent("download.pdf")
  try? FileManager.default.moveItem(at: location, to: dest)
}

后台应用刷新处理程序

在 AppDelegate 中保存后台完成处理程序,并在所有任务完成后调用它。

func application(_ app: UIApplication, handleEventsForBackgroundURLSession id: String, completionHandler: @escaping () -> Void) {
  backgroundCompletionHandler = completionHandler
}
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
  DispatchQueue.main.async { self.backgroundCompletionHandler?() }
}

使用后台会话的下载任务

在后台会话上使用 downloadTask(with:),以可靠地下载大型文件。

let task = session.downloadTask(with: URL(string: "https://cdn.example.com/large.zip")!)
task.resume()

后台上传任务

后台会话也支持上传任务,即使应用未运行,上传仍可继续。

var request = URLRequest(url: uploadURL)
request.httpMethod = "POST"
let task = session.uploadTask(with: request, fromFile: localFileURL)
task.resume()

监控进度

观察 URLSessionTaskDelegate,以跟踪上传或下载进度并更新界面。

func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
  let progress = Double(totalBytesSent) / Double(totalBytesExpectedToSend)
  DispatchQueue.main.async { self.uploadProgress = progress }
}

结合重试与后台任务

对 API 调用使用前台重试,对长时间运行的下载或上传使用后台会话。

// API calls: async/await + exponential backoff retry
// Large downloads: URLSessionConfiguration.background + delegate

快速检查

哪种技术可以防止重试的客户端在同一时刻全部访问服务器?

课程回顾

对瞬时性错误使用指数退避加抖动来实现重试。只重试 5xx 错误和超时错误。对必须在应用挂起期间继续运行的下载或上传,使用带代理的 URLSessionConfiguration.background。

常见问题解答

「重试逻辑与后台 URLSession」课时是免费的吗?

是的 — 「重试逻辑与后台 URLSession」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「重试逻辑与后台 URLSession」这节课中我会学到什么?

实现指数退避,并在后台继续下载。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「重试逻辑与后台 URLSession」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 async/await 调用 URLSession data(from:)
  2. Codable:编码与解码 JSON
  3. 错误处理与 HTTP 状态码
  4. 重试逻辑与后台 URLSession
← 返回 Swift Academy