重试逻辑与后台 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 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 async/await 调用 URLSession data(from:)
- Codable:编码与解码 JSON
- 错误处理与 HTTP 状态码
- 重试逻辑与后台 URLSession