objective-cswiftnsurlsessionnsurlsessiondownloadtasknsurlsessiondatatask

How to use URLSession downloadTaskWithResumeData to start download again when AfterdidCompleteWithError Called..?


I have the code to download two files from Server and store It to In local using URLSession (let dataTask = defaultSession.downloadTask(with: url)). Everything Is working fine only the problem is it's downloading first file it's giving me success but the second file is not downloading completely.. So, I hope there is a way to restart download for the second file that gives error ..

I think there is way of doing that and start looking into it and I found this delegate method .. but not much help .. can anyone please help me out how to restart download if it fails .. Do i have to use handleEventsForBackgroundURLSession to clear up previous downloads..?

// bellow download method will triggered when i get filenames I am passing it to this and path is optional here..

  func download(path: String?, filenames: [String]) -> Int {
    for filename in filenames {
      var downloadFrom =  "ftp://" + username! + ":"
      downloadFrom += password!.addingPercentEncoding(withAllowedCharacters: .urlPasswordAllowed)! + "@" + address!

      if let downloadPort = port {
          downloadFrom += ":" + String(downloadPort) + "/"
      } else {
        downloadFrom += "/"
      }

      if let downloadPath = path  {
        if !downloadPath.isEmpty {
          downloadFrom +=  downloadPath + "/"
        }
      }
      downloadFrom += filename

      if let url = URL(string: downloadFrom) {
        let dataTask = defaultSession.downloadTask(with: url)
        dataTask.resume()
      }
    }
    return DLResponseCode.success
  }

Please find delegate methods bellow ..

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {

    var responseCode = DLResponseCode.success

    // Move the file to a new URL
    let fileManager = FileManager.default
    let filename = downloadTask.originalRequest?.url?.lastPathComponent
    let destUrl = cacheURL.appendingPathComponent(filename!)
    do {

      let data = try Data(contentsOf: location)

      // Delete it if it exists first
      if fileManager.fileExists(atPath: destUrl.path) {
        do{
          try fileManager.removeItem(at: destUrl)
        } catch let error {
          danLogError("Clearing failed downloadFOTA file failed: \(error)")
          responseCode = DLResponseCode.datalogger.failToCreateRequestedProtocolPipe
        }
      }
      try data.write(to: destUrl)
    } catch {
      danLogError("Issue saving data locally")
      responseCode = DLResponseCode.datalogger.noDataConnection
    }


    // Complete the download message
    let message = DLBLEDataloggerChannel.Commands.download(responseCode: responseCode).description
    connectionManagerDelegate?.sendMessageToDatalogger(msg: message)

  }

  func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {

    if error == nil {
        print("session \(session) download completed")
    } else {
        print("session \(session) download failed with error \(String(describing: error?.localizedDescription))")


       // session.downloadTask(withResumeData: <#T##Data#>)
    }
    guard error != nil else {
      return
    }

    danLogError("Session \(session) invalid with error \(String(describing: error))\n")
    let responseCode = DLResponseCode.datalogger.failToCreateRequestedProtocolPipe
    let message = DLBLEDataloggerChannel.Commands.download(responseCode: responseCode).description
    connectionManagerDelegate?.sendMessageToDatalogger(msg: message)
  }

// When I call didWriteData delegate method it's printing below data seems not dowloaded complete data ..

session <__NSURLSessionLocal: 0x103e37970> download task <__NSCFLocalDownloadTask: 0x108d2ee60>{ taskIdentifier: 2 } { running } wrote an additional 30028 bytes (total 988980 bytes) out of an expected 988980 bytes.

//error that I am getting for second file .. this error is coming some times not always but most of the times..

session <__NSURLSessionLocal: 0x103e37970> download failed with error Optional("cancelled")

Please help me out to figure it out .. If there is any way to handle download again after it fails or why it fails ..


Solution

  • The resume data, if the request is resumable, should be in the NSError object's userInfo dictionary.

    Unfortunately, Apple seems to have completely trashed the programming guide for NSURLSession (or at least I can't find it in Google search results), and the replacement content in the reference is missing all of the sections that talk about how to do proper error handling (even the constant that you're looking for is missing), so I'm going to have to describe it all from memory with the help of looking at the headers. Ick.

    The key you're looking for is NSURLSessionDownloadTaskResumeData.

    If that key is present, its value is a small NSData blob. Store that, then use the Reachability API (with the actual hostname from that request's URL) to decide when to retry the request.

    After Reachability tells you that the server is reachable, create a new download task with the resume data and start it.