mcfly soft
mcfly soft

Reputation: 11665

downloadTaskWithRequest confusing behaviour (swift , IOS )

I do not understand the following and hope some does :-)

I am downloading a file from an url (10 minutes downloadtime), which works fine, when the download completes.

BUT: When I simulate a crash or internet-interruption after a minute and restart the app again, it behaves strange to me. In this case when restarting my app to download again with same sessionid, it seems that 2 download tasks are working in parallel. I recognizue this with a jumping progressbar from 10% to 0% and back. One, which starts from scratch and one, which I guess continious the old transfer. (not sure). I can restart again and then there is one more in the queue.

Can someone confirm this behaviour and does someone know how I can: - continue only the interrupted download task (preferred :-) ) - or how can I start from scratch only.

Here my code for downloading, which works fine without any interruption.

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()

}

Update When I am using a different sessionid, the Download starts from scratch. The previously started download task runs still in the background. So I am wondering why can't I resume the previously download task by using the old sessionid without starting a new download in parallel ?

Upvotes: 1

Views: 672

Answers (2)

Rob
Rob

Reputation: 438287

In addition to what dgatwood said, remember to have to have your app delegate implement application:handleEventsForBackgroundURLSession:completionHandler:, which is called if the download finishes and your app isn't running at the time. When this method is called (again, only if download finishes when your app wasn't running), you should (a) save the completionHandler; (b) instantiate the background session with the same identifier; (c) let your NSURLSessionDownloadDelegate method be called (at which point which didFinishDownloadingToURL: is called) and when (d) URLSessionDidFinishEventsForBackgroundURLSession is called, if you have a completionHandler saved from when handleEventsForBackgroundURLSession was called, then this is the appropriate time to call this saved completionHandler.

The basic idea is as follows: If your app wasn't already running when the download finishes, the OS seamlessly starts your app in the background (unbeknownst to the end user), providing a reference to this completionHandler, you then have the app do all that it needs to do to move this downloaded file to its new location, and when it's all done, you call the saved completionHandler to let the OS know that you're all done handling the downloaded file in the background execution and the app can safely be suspended again (i.e. to avoid keeping the app running in the background, adversely affecting the UX and battery for the user).

Obviously, if the app happens to be running and has the NSURLSession already instantiated, you won't see these background related events taking place. If the app was running when the download finishes, it behaves much like a foreground NSURLSession and the above is not called upon. But you need that logic in case your app wasn't running when the download finishes.

See Downloading Content in the Background section of The App Programming Guide for iOS, which describes this process. Also refer to WWDC 2013 video in What’s New in Foundation Networking (it's covered later in the video).

Upvotes: 1

dgatwood
dgatwood

Reputation: 10417

The whole point of using a download task is so that downloads can continue even if your app isn't running or if it crashes. You don't need to resume the download. It is actually happening in a separate background daemon. You just need to re-create the session using the same ID.

After you re-create the session, any existing downloads are automatically associated with the new session, and your delegate methods are called whenever the task completes.

There's also a little bit of magic that you need to implement for handling background launches if your app isn't running when the download finishes. See URL Session Programming Guide for details.

Upvotes: 1

Related Questions