4

I would like to track the progress of videos uploaded through a stream request with a UIProgressView. Unfortunately, I am not using Alamofire, so I'm not sure if URLSession has this ability. Below is relevant code from my application.

func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {

    let uploadProgress:Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
    let uploadCell = contentTableView.cellForRow(at: IndexPath(row: 0, section: 0)) as! NewContentCell
    uploadCell.uploadProgressView.progress = uploadProgress


}

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    let uploadCell = contentTableView.cellForRow(at: IndexPath(row: 0, section: 0)) as! NewContentCell
    uploadCell.uploadProgressView.progress = 1.0
}

didCompleteWithError correctly sets the UIProgressView to indicate that the upload is complete, however, didSendBodyData is returning values greater than 1 through the uploadProgress calculation.

It's my first time utilizing a stream request, so I'm hoping I simply glossed over something that you could help point out. Here is the structure of my request as well for reference.

let request = NSMutableURLRequest(url: NSURL(string: "\(requestUrl)")! as URL,
                                          cachePolicy: .useProtocolCachePolicy,
                                          timeoutInterval: 10.0)
        request.httpMethod = "POST"
        request.allHTTPHeaderFields = headers
        request.httpBodyStream = InputStream(data: body as Data)

        let configuration = URLSessionConfiguration.default
        let session = URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
        let dataTask = session.uploadTask(withStreamedRequest: request as URLRequest)
        dataTask.resume()

Much thanks for your input and help.

iMoment
  • 243
  • 1
  • 4
  • 14

2 Answers2

3

Implementing

public func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)

is the correct way to track stream request progression.

But if you want to now the totalBytesExpectedToSend, you must tell it to the server. So don't forget to set the correct Content-Length header in your request!

Here's the way i'm creating the request:

var request = URLRequest(url: url)
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
request.addValue(String(dataToUpload.count), forHTTPHeaderField: "Content-Length") // <-- here!
request.httpBodyStream = InputStream(data: dataToUpload)
var task = session.uploadTask(withStreamedRequest: request)
task?.resume()
Martin
  • 11,881
  • 6
  • 64
  • 110
1

Reading documentation further, figured out that stream objects do not support totalBytesExpectedToSend. It may be a hack, but just using the file's NSData.length feature allows for correct progress tracking. So for stream requests using URLSession, progress can be tracked by using didSendBodyData, with let uploadProgress: Float = Float(totalBytesSent) / Float(mediaSize), where mediaSize is NSData.length.

iMoment
  • 243
  • 1
  • 4
  • 14
  • how did you track you stream progression? `func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)` is never called on stream tasks! – Martin May 24 '17 at 08:35
  • Ooops. I just forgot to call `streamTask.resume()` – Martin May 24 '17 at 09:19