NSURLSession with DataTask Delegate返回预期内容长度为负(-1),无法计算文件大小

时间:2015-04-01 23:29:50

标签: ios objective-c swift progress-bar nsurlsession

我正在尝试使用此后续委托方法计算进度条dataTaskWithURL中正在接收的数据:NSURLSessionTaskDelegate, NSURLSessionDataDelegate,这是我在视图didload中使用的代码,I我没有使用请求。 网址:http://www.roimulia.com/db.php 全球物业:

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

相关代表方法:

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

调试后,我发现进度条没有加载,即使数据是完全收到的。发生这种情况的原因是因为response.expectedContentLength的值等于-1,这意味着当服务器上的文件被压缩时,长度的默认值就会出现。

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

ROB ANSWER更新:

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

首先,忘记我在下面评论的内容,我错过了你写的东西。 Rob建议3个答案。正如我所看到的,答案号 2 是我正在寻找的,因为它使用委托方法,并且因为我计划用这个应用程序去大,我需要让它像我一样高效可以(除非我错了,请参考这一行,我真的关心从网上下载/接收数据的效率)。 所以我发现了两件有趣的事情: 1)当我在请求中使用文件作为在我的服务器上找到并解析为json时 - 与 http://roimulia.com/db.php 一样,它确实在didCompleteWithError委托方法,我可以使用NSJSONSerialization.JSONObjectWithData来获取数据。 但是 expectedContentLength等于-1,所以我无法计算它的进度。 但是,当我使用此链接进行exmaple(在我的服务器上找到) http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo - 它完全加载时,expectedContentLength不是eqal - 1,我可以计算它的进展。 所以结论一:1)问题可能连接到我的服务器或我在php文件中回显我的数组的方式(虽然我可以使用最后的数据,所以它很奇怪)。 让我知道你对此的看法) 2)如果我们无法通过解决方案2解决它

1)与解决方案2相比,其他两个解决方案(1,3)的效率(下载速度,进度等)效率较低,如果有的话

我希望它现在足够详细:X我等不及要解决它

1 个答案:

答案 0 :(得分:0)

正确。如果压缩,则没有预期的内容长度。

  1. 您可以将Accept-Encoding标题设置为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()
    

    应该注意的是,即使这样,您也可能无法获得有效的expectedContentLength(例如,不确定长度的分块响应),但通常它会起作用。

  2. 或者,为了获得进度视图而不是减慢下载速度,您可能希望显示在收到数据时移动的内容,让用户知道正在接收实际数据,但是循环:

    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. 由于您有一个提供此下载的PHP Web服务,理论上您可以让您的服务器确定下载的未压缩大小,并以某种方式将其包含在响应中(自定义标头,其他一些API)回复它的电话,等等。)