1

I'm trying to calculate the data that is being received in dataTaskWithURL for a progress bar using this follow up delegate method: NSURLSessionTaskDelegate, NSURLSessionDataDelegate, this is the code I use in the view didload, I'm not using request. web adress : http://www.roimulia.com/db.php Global properties :

var dataTodownload : NSMutableData!
var downloadSize : Float!

ViewDidload :

var defaultConfigObject : NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
var  defaultSession  : NSURLSession = NSURLSession(configuration: defaultConfigObject, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let url = NSURL(string: "http://www.roimulia.com/db.php")
var datatask = defaultSession.dataTaskWithURL(url!)
datatask.resume()

Relevant Delegate methods :

   func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void)
    {
        completionHandler(NSURLSessionResponseDisposition.Allow)
        prgs_bar.progress = 0
        downloadSize = Float(response.expectedContentLength)
        dataTodownload = NSMutableData()           
    }

    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
    {
        dataTodownload.appendData(data)
        prgs_bar.progress = Float(dataTodownload.length) / Float(downloadSize)
    }

After debugging I found out that the progress bar doesn't load, even if the data was received completely. The reason it's happening is because the value of response.expectedContentLength equals -1, which means something about the default value of the length when it the file on the server is compressed.

==============================

UPDATE BY ROB ANSWER :

==============================

So as a start, forget what i have commented below , i missed something you wrote. Rob suggested 3 answers. As i see it, answer number 2 is the one i'm looking for, Because it uses delegate method, and because im planning to go big with this app, I need to make it as efficient as i can (Unless and i'm wrong, please refer to this line too, I really care about efficiency of Download/receive data from the web). So i found out 2 interesting things : 1)When i use a file as the url in the request that locate on my server and parsed as json - as for http://roimulia.com/db.php it does receive the data at didCompleteWithError delegate method, and i can use NSJSONSerialization.JSONObjectWithData to get the data out. BUT the expectedContentLength equals -1 , so i cant calculate it progress. But when i use this link for exmaple(not locate on my server) http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo - It loads with perfectly) , expectedContentLength is not eqal -1 , and i can calaculate it progress . So conclusion one : 1) The problem might be connected to my server or to the way i echo my Array at the php file(although i can use the data at the end so it's weird). Let me know what you think about that) 2) If we couldnt solve it via solution number 2 :

1)How much the two others solutions (1 , 3) are less efficient (as for download speed , progress, etc) compare to solution 2, If any?

I hope it detail enough for now :X I cant wait to solve it

Jackky White
  • 357
  • 1
  • 4
  • 11
  • You ask if using `identity` is really slower: Why don't you just benchmark it and see? Theoretically it might be slower if it's not compressed, but given that much of the overall network response time is network latency, it might not be material unless the response is very large. – Rob Apr 03 '15 at 01:35
  • @Rob , what about the possible solution for your number 2? Did we gave up about it? i tried everything lol but my knowledge isnt great as your's , so you think we have hope on this 1 or 3 is what we got left? – Jackky White Apr 03 '15 at 01:56
  • I didn't give up on it. It's the technique I use when expected length is unknown. You say it doesn't work for you, but you don't say in what way, so I'm not sure what further you expect me to say in the topic. – Rob Apr 03 '15 at 02:00
  • @Rob , i said , that it still return -1 for the length (for the 2 solution) , although i printed the respone and it said the followng : eceived response: { URL: http://www.roimulia.com/db.php } { status code: 200, headers { Connection = close; "Content-Encoding" = gzip; "Content-Length" = 2598; "Content-Type" = "text/html"; Date = "Fri, 03 Apr 2015 01:43:34 GMT"; Server = "Apache/2"; Vary = "Accept-Encoding,User-Agent"; "X-Powered-By" = "PHP/5.3.29"; } } – Jackky White Apr 03 '15 at 02:04
  • @Rob We can see that content-Length is 2598 , it's what we need dont we? – Jackky White Apr 03 '15 at 02:05
  • It depends upon how you got that `Content-Length`. Look at the size of the resulting `NSMutableData` and compare to the `Content-Length`. By the way, if your `Content-Length` is 2598 bytes, the performance difference between compressed and uncompressed is almost certainly not statistically significant. Likewise a progress view showing the progress is probably not very meaningful. If it was megabytes (or even hundreds of kilobytes) compression might have observable impact in performance. But not with something this small. – Rob Apr 03 '15 at 02:48
  • @Rob , well thats depends, Maybe we can understand which delegate i need to use (Data or Download) for the following scenario. At the end point , what i'm trying to do is make a news feed that acts like instagram. (Table view that loads into the cell for example username and the image. So i thought about something like that , for all the strings (etc img url , username) using data task (because its only strings so it wont weight much) , and then sent a download request of the urls and save the images locally (On NSCache or Doucment Directory) . Is it a good logic? – Jackky White Apr 03 '15 at 14:38

1 Answers1

1

Correct. You do not have expected content length if it is compressed.

  1. You can turn off compression by setting Accept-Encoding header to identity:

    let url = NSURL(string: "http://www.roimulia.com/db.php")
    let request = NSMutableURLRequest(URL: url!)
    request.setValue("identity", forHTTPHeaderField: "Accept-Encoding")
    
    let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
    
    let task = session.dataTaskWithRequest(request)
    task.resume()
    

    It should be noted that, even then, you might not get a valid expectedContentLength (e.g. chunked response of indeterminate length), but generally it will work.

  2. Alternatively, rather than slowing down the download for the sake of a progress view, you might want to show something that moves as data is received, letting the user know that there is actual data being received, but have it loop:

    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        dataTodownload.appendData(data)
    
        var progress: Float!
    
        if downloadSize < 0 {
            progress = (Float(dataTodownload.length) % 10_000_000.0) / 10_000_000.0
        } else {
            progress = Float(dataTodownload.length) / downloadSize
        }
    
        progressView.progress = progress
    }
    
  3. Since you have a PHP web service delivering this download, you theoretically could have your server determine what the uncompressed size of the download was going to be, and include that in the response somehow (custom header, some other API call that returns it, etc.).

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Hey Rob! thanks for very detail answer , unfortunately the second method(that i think suited me best , because it dosent "slow the download") dosent work for me , even with a link that it have worked before(not the one on my server). I think you have a missing row at the DidRecieveData function , on the Else -> dataTodownload.appendData(data) maybe that's the problem? – Jackky White Apr 02 '15 at 06:53
  • UPDATE : So i tried the second method with diffrent link(not from my server) like this one -> http://blog.teamtreehouse.com/api/get_recent_summary , with the fixed value from my first answer (answer above) , and it work's. But for my server(http://www.roimulia.com/db.php) it dosent work. Could it be problem with my php? If not, Can you explain further if you may , on using the first method? how do i use "identity" , and how much slower using the first method is than the second? :D Thanks! im sure this question will help bunch of people lol – Jackky White Apr 02 '15 at 06:59
  • Rob i added update , i hope it will explained , thank you for your time . Honestly . @Rob – Jackky White Apr 02 '15 at 23:51