Search code examples
swiftuser-interfacedispatchurlsession

UI update not working for urlSession downloadTask didWriteData


Currently, I've got a problem with the update of the user interface when using a download task. The following function should update the user interface, but it works just sometimes. Why doesn't it work every time I download a file? The log of NSLog is shown in the debugger every time!

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
  let curDownloadSize = totalBytesWritten / (1024*1024)
  let totalDownloadSize = totalBytesExpectedToWrite / (1024*1024)

  if curDownloadSize != oldDownloadSize {
    DispatchQueue.main.async {
      self.progressLabel!.text = "\(self.curDownloadSize)MB / \(self.totalDownloadSize)MB"
      self.progressView!.progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
      NSLog("Download progress: \(Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))");
    }
  }
}

progressLabel and progressView are both available at this time.

BTW, I have tested it with the same file multiple times and sometimes it works, sometimes it doesn't.

Update: I read about using a second dispatch queue like this

DispatchQueue.global(qos: .utility).async {
  DispatchQueue.main.async {
    (same as above)
  }
}

but this is also working just sometimes.


Solution

  • Recently, I solved the problem.

    The problem occurs if too many events are pushed to the main queue. It just occurred with a very good internet connection. In this case the callback has been called too often.

    My solution:

    progressCounter += 1
    if progressCounter % 30 == 0 {
      DispatchQueue.main.async {
        self.progressLabel!.text = "\(self.curDownloadSize)MB / \(self.totalDownloadSize)MB"
        self.progressView!.progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
        NSLog("Download progress: \(Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))");
      }
    }
    

    The progressCounter has been initialized to 0 before.