Ios DataTask委托的NSURLSession返回expectedContentLength负值(-1),无法计算文件大小

Ios DataTask委托的NSURLSession返回expectedContentLength负值(-1),无法计算文件大小,ios,objective-c,swift,progress-bar,nsurlsession,Ios,Objective C,Swift,Progress Bar,Nsurlsession,我正在尝试使用以下后续委托方法计算在dataTaskWithURL中接收的进度条数据:nsurlSessionAskDelegate,NSURLSessionDataDelegate,这是我在视图didload中使用的代码,我没有使用请求。 网址: 全局属性: var dataTodownload : NSMutableData! var downloadSize : Float! ViewDidload: var defaultConfigObject : NSURLSessionConfi

我正在尝试使用以下后续委托方法计算在
dataTaskWithURL
中接收的进度条数据:
nsurlSessionAskDelegate,NSURLSessionDataDelegate
,这是我在视图didload中使用的代码,我没有使用请求。 网址: 全局属性:

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更新答案:

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

所以作为一个开始,忘记我在下面的评论,我错过了你写的东西。 罗布提出了3个答案。在我看来,答案编号2是我正在寻找的答案,因为它使用委托方法,而且因为我计划使用这个应用程序,我需要尽可能提高效率(除非我错了,请也参考这一行,我真的很关心从web下载/接收数据的效率)。 所以我发现了两件有趣的事情: 1) 当我使用一个文件作为请求中的url时,位于我的服务器上,并解析为json-对于,它确实会在DidCompleteWitheror委托方法中接收数据,我可以使用
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我迫不及待地要解决它

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

  • 通过将
    接受编码
    标题设置为
    标识
    ,可以关闭压缩:

    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
    (例如,长度不确定的分块响应),但通常情况下它会起作用

  • 或者,与其为了进度视图而减慢下载速度,不如显示接收数据时移动的内容,让用户知道接收到的是实际数据,但让它循环:

    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
    }
    
    func-URLSession(会话:NSURLSession,数据任务:NSURLSessionDataTask,didReceiveData数据:NSData){
    dataTodownload.appendData(数据)
    变量进度:浮动!
    如果下载大小<0{
    进度=(浮动(dataTodownload.length)%10\u 000\u 000.0)/10\u 000\u 000.0
    }否则{
    进度=浮动(dataTodownload.length)/downloadSize
    }
    progressView.progress=进度
    }
    
  • 由于您有一个PHP web服务提供此下载,理论上,您可以让服务器确定下载的未压缩大小,并以某种方式将其包含在响应中(自定义头、返回此下载的其他API调用等)


  • 嘿,罗布!感谢您提供了非常详细的答案,不幸的是,第二种方法(我认为最适合我,因为它会“减缓下载”)对我来说不起作用,即使有一个它以前使用过的链接(不是我服务器上的链接)。我想您在Else->dataTodownload上的didReceiveData函数缺少一行。appendData(data)可能就是问题所在?更新:所以我尝试了第二种方法,使用Different link(不是从我的服务器上)像这样的->,使用我的第一个答案(上面的答案)中的固定值,它工作正常。但对于我的服务器()来说,它不起作用。这可能是我的php有问题吗?如果没有,您是否可以进一步解释,关于使用第一种方法?如何使用“标识”,以及使用第一种方法比使用第二种方法慢多少D谢谢!我相信这个问题会帮助很多人,我补充了更新,我希望它会解释,谢谢你的时间。老实说@如果您问使用
    identity
    是否真的比较慢:为什么不对其进行基准测试并查看一下呢?从理论上讲,如果不进行压缩,它可能会变慢,但考虑到整个网络响应时间的大部分是网络延迟,除非响应非常大,否则它可能不是实质性的。@Rob,你的2号问题的可能解决方案是什么?我们放弃了吗?我尝试了一切,哈哈,但是我的知识没有你的那么好,所以你认为我们在这方面有希望1或3是我们剩下的吗?我没有放弃。这是我在预期长度未知时使用的技术。你说它不适合你,但你没有说以什么方式,所以我不确定你希望我在这个主题中说什么。@Rob,我说,它仍然返回-1的长度(对于2的解决方案),尽管我打印了响应,它说下面的:eceived响应:{URL:}{状态代码:200,标题{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=“Acce