>我在后台下载zip文件:
if let url = NSURL(string: urlstring)
{
let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier((NSUUID().UUIDString))
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
let task = session.downloadTaskWithURL(url)
session.sessionDescription = filepath
if let sessionId = session.configuration.identifier
{
print("start zip session: " + sessionId)
}
task.resume()
}
}
如果您有互联网连接,它可以很酷,但如果您在下载应用程序期间丢失了它,只需等待和URLSession(会话:NSURLSession,任务:NSURLSessionTask,didCompleteWithError error:NSError?(将不会被称为永远不会。如何处理?
类似于服务器响应的时间
这个问题很老,但仍然没有答案,所以这里有一个解决方法。
先澄清一些
通常,URLSessionConfiguration
有一个称为waitsForConnectivity
的属性,可以将其设置为false
,然后URLSessionTask
在连接丢失时将直接失败。但是,如果true
,则URLSessionTaskDelegate
将收到urlSession(_:taskIsWaitingForConnectivity:)
方法的回调。
然而
后台任务(如DownloadTask
(始终等待连接并忽略waitsForConnectivity
URLSessionConfiguration
的属性。它们也不会触发urlSession(_:taskIsWaitingForConnectivity:)
回调,因此没有官方方法来侦听下载任务上的连接中断。
解决方法
如果您侦听下载进度,您会注意到对该方法的调用在一秒钟内完成几次。因此,我们可以得出结论,如果调用进度回调的时间超过 5 秒,则可能存在连接丢弃问题。因此,解决方法是向URLSessionDownloadDelegate
委托创建其他属性并存储进度的上次更新。然后具有间隔功能,定期检查此属性是否未很快更新。
像这样:
class Downloader: NSObject, URLSessionTaskDelegate, URLSessionDownloadDelegate {
var lastUpdate: Date;
var downloadTask: URLSessionDownloadTask?;
public var session : URLSession {
get {
let config = URLSessionConfiguration.background(
withIdentifier: "(Bundle.main.bundleIdentifier!).downloader");
config.isDiscretionary = true;
return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue());
}
}
override init() {
self.lastUpdate = Date();
super.init();
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
// Handle download completition
// ...
}
func urlSession(
_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten writ: Int64,
totalBytesExpectedToWrite exp: Int64)
{
let progress = 100 * writ / exp;
// Do something with the progress
// ...
self.lastUpdate = Date();
}
}
var downloader = Downloader();
let url = "http://...";
var request = URLRequest(url: URL(string: url)!);
currentWorker.downloadTask = downloader.session.downloadTask(with: request);
currentWorker.downloadTask!.resume();
// Schedule timer for every 5 secs
var timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "CheckInternetDrop", userInfo: nil, repeats: true);
func CheckInternetDrop(){
let interval = Date().timeIntervalSinceDate(downloader.lastUpdate);
if (interval > 5) {
print("connection dropped");
}
}
非常简单的例子...
根据苹果关于暂停和恢复下载的文档:
此外,使用后台配置的下载将自动处理恢复,因此只有非后台下载才需要手动恢复。
此外,等待连接被忽略的原因在后台下载文件中说明:
如果您的应用在后台运行,则在另一个进程中执行下载时,系统可能会挂起您的应用。
这就是为什么即使您以类似于Dimitar Atanasov的方式构建计时器,一旦应用程序进入后台,它也不会工作,因为它将被挂起。
我已经测试了后台下载自己与网络故障,系统恢复没有失败,因此不需要额外的代码。
您可以为请求设置超时:
config.timeoutIntervalForRequest = <desired value>
config.timeoutIntervalForResource = <desired value>
文档:
- timeoutIntervalForRequest
- timeoutIntervalForResource