【问题标题】:downloadTaskWithRequest confusing behaviour (swift , IOS )downloadTaskWithRequest 令人困惑的行为(swift,IOS)
【发布时间】:2015-10-27 14:49:27
【问题描述】:

我不明白以下内容,希望有些人明白:-)

我正在从一个 url 下载一个文件(下载时间为 10 分钟),下载完成后效果很好。

但是: 当我在一分钟后模拟崩溃或互联网中断并再次重新启动应用程序时,它的行为对我来说很奇怪。 在这种情况下,当重新启动我的应用程序以使用相同的 sessionid 再次下载时,似乎 2 个下载任务正在并行工作。我通过从 10% 到 0% 并返回的跳跃进度条来识别这一点。一个,从头开始,一个,我猜是旧的转移。 (没有把握)。我可以重新启动,然后队列中还有一个。

有人可以确认这种行为吗?有人知道我该怎么做: - 仅继续中断的下载任务(首选:-)) - 或者我怎样才能从头开始。

这是我的下载代码,它可以正常工作而没有任何中断。

func download_file(sURL: String, sToLocation: String) {

    println("start downloading ...");
    println("sURL : " + sURL + " sToLocation : " + sToLocation);
    bytesDownloaded=0;

    var delegate = self;
    delegate.storePath=sToLocation;
    delegate.progressView=progressView;
    struct SessionProperties {
        static let identifier : String! = "url_session_background_download"
    }
    var configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(SessionProperties.identifier)
    var backgroundSession = NSURLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
    //myURLSession = NSURLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
    var url = NSURLRequest(URL: NSURL(string: sURL)!)
    var downloadTask = backgroundSession.downloadTaskWithRequest(url)

    //downloadTask.cancel()

    downloadTask.resume()

}

更新 当我使用不同的 sessionid 时,下载从头开始。之前启动的下载任务仍在后台运行。所以我想知道为什么我不能通过使用旧的 sessionid 来恢复以前的下载任务而不并行开始新的下载?

【问题讨论】:

    标签: ios swift download background nsurlsession


    【解决方案1】:

    使用下载任务的全部意义在于,即使您的应用未运行或崩溃,下载也可以继续进行。您无需继续下载。它实际上发生在一个单独的后台守护进程中。您只需要使用相同的 ID 重新创建会话。

    在您重新创建会话后,任何现有下载都将自动与新会话相关联,并且每当任务完成时都会调用您的委托方法。

    如果您的应用在下载完成时没有运行,您还需要实现一些魔法来处理后台启动。详情请见URL Session Programming Guide

    【讨论】:

    • 我不确定,但我想我明白了。我的下载任务大约需要 10 分钟。当我在 1 分钟后在下载过程中退出我的应用程序并立即使用我识别的相同会话标识符重新启动时,旧的下载会恢复,但另外一个新的下载会并行启动。我可以从进度条中看到这一点,从 10% 跳到 0% 并返回,因为我的处理程序被调用了两次。我预计只会看到一个进度 -> 恢复任务的 10%。你看到我的冲突了吗?
    • 是的。问题是你总是这样做: var downloadTask = backgroundSession.downloadTaskWithRequest(url)
    • 相反,要么在 NSUserDefaults 中存储一些东西来告诉自己传输正在进行中(然后不要启动它),要么在会话上调用 getTasksWithCompletionHandler: 以找出是否有活动任务,并且根据你在回调中获得的任务来决定是否启动它。
    • 我猜我理解的逻辑。问题是当我尝试恢复旧的下载任务时,我必须在第二次启动时调用什么。此时下载尚未完成(仍需 9 分钟)。代替 var downloadTask = backgroundSession.downloadTaskWithRequest(url) ,我应该怎么称呼?
    • 啊。您只需创建配置、创建会话并设置委托。该任务会自动与新会话关联,并且在它完成时调用您的委托方法,就像您的应用程序从未退出一样。所以基本上所有事情都包括但不包括创建 URL 请求和下载任务。
    【解决方案2】:

    除了 dgatwood 所说的之外,请记住必须让您的应用代理实现 application:handleEventsForBackgroundURLSession:completionHandler:,如果下载完成并且您的应用当时没有运行,则会调用该代理。当调用此方法时(同样,仅当您的应用未运行时下载完成),您应该 (a) 保存 completionHandler; (b) 用相同的标识符实例化后台会话; (c) 让您的NSURLSessionDownloadDelegate 方法被调用(此时调用didFinishDownloadingToURL:)以及何时调用(d)URLSessionDidFinishEventsForBackgroundURLSession,如果您从调用handleEventsForBackgroundURLSession 时保存了completionHandler,那么这是调用此已保存completionHandler 的适当时间。

    基本思路如下:如果下载完成时您的应用尚未运行,则操作系统会在后台无缝启动您的应用(最终用户不知道),提供对此completionHandler的引用,您然后让应用程序执行将下载的文件移动到新位置所需的所有操作,完成后,您调用保存的completionHandler 让操作系统知道您已完成对下载文件的处理后台执行和应用程序可以安全地再次暂停(即避免让应用程序在后台运行,对用户的用户体验和电池产生不利影响)。

    显然,如果应用程序恰好正在运行并且已经实例化了 NSURLSession,您将不会看到这些与背景相关的事件正在发生。如果下载完成时应用程序正在运行,它的行为很像前台NSURLSession,并且不会调用上述内容。但您需要该逻辑以防下载完成时您的应用未运行。

    请参阅iOS 应用程序编程指南Downloading Content in the Background 部分,其中描述了此过程。另请参阅What’s New in Foundation Networking 中的 WWDC 2013 视频(视频稍后会介绍)。

    【讨论】:

    • 非常感谢您的解释。我想我需要一些时间来了解这一点。但我想我理解的一般方法。目前让我感到困惑的是,即使我的应用程序已经完成,也会在 Bckground 中调用一个 complitionHandler。但是我会尝试。谢谢。
    • @mcflysoft 我试图澄清我的答案以解释completionHandler 的目的。
    猜你喜欢
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-20
    • 1970-01-01
    • 2015-10-22
    相关资源
    最近更新 更多