You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

触发didCompleteWithError后,如何用URLSession downloadTaskWithResumeData重启下载?

解决URLSession下载失败后用ResumeData重启的问题

Hey there! Let's walk through how to resume that failed second download using resumeData with URLSession, since you're stuck getting it to complete.

第一步:捕获下载失败时的ResumeData

当下载任务失败并触发urlSession(_:task:didCompleteWithError:)代理方法时,不是所有错误都能恢复,但如果服务器支持断点续传,系统会把恢复所需的resumeData放在错误对象的userInfo里。你需要从这里提取它:

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    guard let error = error else {
        // 任务成功完成,无需处理
        return
    }
    
    // 从错误信息中提取resumeData
    if let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
        // 把resumeData存起来(可以存在属性、UserDefaults或本地文件)
        self.pendingResumeData = resumeData
        // 立即重启或者等待用户触发
        restartFailedDownload()
    } else {
        // 没有可用的resumeData,比如服务器不支持断点续传、URL无效等
        print("无法恢复下载:\(error.localizedDescription)")
        // 这种情况只能从头重新发起下载
        startFreshDownloadForSecondFile()
    }
}

第二步:用ResumeData重启下载

拿到有效的resumeData后,你可以用downloadTask(withResumeData:)创建一个新的下载任务,然后调用resume()启动它。这里可以用闭包或者代理模式,和你原来的下载逻辑保持一致就行:

func restartFailedDownload() {
    guard let resumeData = self.pendingResumeData else { return }
    
    // 创建恢复任务(这里用闭包示例,你也可以用代理模式)
    let resumeTask = defaultSession.downloadTask(withResumeData: resumeData) { [weak self] fileLocation, response, error in
        guard let fileLocation = fileLocation, error == nil else {
            print("重启下载失败:\(error?.localizedDescription ?? "未知错误")")
            return
        }
        
        // 把临时文件移到你的目标存储路径(替换成你自己的路径逻辑)
        guard let destinationURL = self?.getDestinationURL(for: response) else { return }
        
        do {
            // 先删除已存在的文件(如果有的话)
            if FileManager.default.fileExists(atPath: destinationURL.path) {
                try FileManager.default.removeItem(at: destinationURL)
            }
            try FileManager.default.moveItem(at: fileLocation, to: destinationURL)
            print("第二个文件下载重启并完成!")
        } catch {
            print("移动下载文件失败:\(error.localizedDescription)")
        }
    }
    
    // 启动恢复任务
    resumeTask.resume()
}

关键注意事项

  • 服务器支持断点续传是前提:只有当服务器返回Accept-Ranges: bytes响应头时,才能生成有效的resumeData。如果第二个文件的服务器不支持,你只能重新发起普通的downloadTask(with: url)。
  • 检查第二个文件的失败原因:先在didCompleteWithError里打印完整的错误信息,看看是网络超时、服务器错误还是URL问题。比如如果是URL无效,那恢复也没用,得先修正URL。
  • 不要长期保存resumeData:有些服务器的resumeData会过期,最好在失败后立即尝试恢复,或者只临时存储。
  • 保持Session一致性:如果用代理模式,恢复任务的URLSession要和原任务用同一个(或者配置相同的Session),避免出现意外问题。

内容的提问来源于stack exchange,提问作者tp2376

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:03:17