当大于几千字节时,NSURLSession URL响应不会被缓存

时间:2014-11-09 16:10:55

标签: ios cocoa swift nsurlsession

我对使用Cocoa进行IOS编程很新,我正在使用Swift。我使用带有自定义委托的NSURLSession数据会话从JSON API获取数据,而不是闭包。使用自定义委托的原因是我必须进行基本身份验证,并且还注入了一个自定义缓存控制标头来控制缓存行为(我的API根本不包括响应中任何与缓存相关的标头)。

所有这一切都很完美,但仅适用于仅调用一次URLSession:dataTask:didReceiveData:方法的请求。一旦我得到几次调用didReceivedData方法的更大响应(大约20-30kBytes),就不会调用URLSession:dataTask:willCacheResponse:completionHandler:方法,因此我的响应不会被缓存。在5分钟内重新发出相同的请求将再次向服务器发出请求,这对于响应仅一次调用didReceiveData的请求不会发生。 URLSession:task:didCompleteWithError:方法被正确调用并在所有情况下都继续。

URLSession的文档:dataTask:willCacheResponse:completionHandler:method(https://developer.apple.com/library/IOs/documentation/Foundation/Reference/NSURLSessionDataDelegate_protocol/index.html#//apple_ref/occ/intfm/NSURLSessionDataDelegate/URLSession:dataTask:willCacheResponse:completionHandler :)说只有在处理请求的NSURLProtocol决定这样做时才会调用此方法,但我真的不明白该怎么做做到这一点。

非常欢迎任何反馈和想法!

这是发出HTTP请求的代码:

    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    config.URLCache = NSURLCache.sharedURLCache()
    //config.URLCache = NSURLCache(memoryCapacity: 512000000, diskCapacity: 1000000000, diskPath: "urlCache")

    let urlString = apiUrlForFilter(filter, withMode: mode, withLimit: limit, withOffset: offset)
    let url = NSURL(string: urlString)

    var policy: NSURLRequestCachePolicy?
    if ignoreCache == true {
        policy = .ReloadIgnoringLocalCacheData
    } else {
        policy = .UseProtocolCachePolicy
    }

    let request = NSURLRequest(URL: url!, cachePolicy: policy!, timeoutInterval: 20)
    let session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
    let task = session.dataTaskWithRequest(request)
    task.resume()

我实现了以下委托功能:

  • URLSession:didReceiveChallenge:completionHandler:处理SSL证书信任,
  • URLSession:task:didReceiveChallenge:completionHandler:处理基本身份验证
  • URLSession:dataTask:didReceiveResponse:completionHandler:读取一些特定的标题并将它们保存为实例变量

另外,重要的代码:

URLSession:dataTask:didReceiveData:在数据到达时为更大的HTTP请求响应而累积数据:

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
    if receivedData == nil {
        receivedData = NSMutableData()
    }
    receivedData!.appendData(data)
    println("did receive data: \(receivedData!.length) bytes")
}

URLSession:dataTask:willCacheResponse:completionHandler:注入我自己的Cache-Control标头:

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: (NSCachedURLResponse!) -> Void) {
    println("willCacheResponse was called")

    let response: NSURLResponse = proposedResponse.response
    let httpResponse = response as NSHTTPURLResponse
    var headers = httpResponse.allHeaderFields

    var modifiedHeaders = headers        
    modifiedHeaders.updateValue("max-age=300", forKey: "Cache-Control")
    let modifiedResponse = NSHTTPURLResponse(URL: httpResponse.URL!, statusCode: httpResponse.statusCode, HTTPVersion: "HTTP/1.1", headerFields: modifiedHeaders)
    let cachedResponse = NSCachedURLResponse(response: modifiedResponse!, data: proposedResponse.data, userInfo: proposedResponse.userInfo, storagePolicy: proposedResponse.storagePolicy)
    completionHandler(cachedResponse)
}

URLSession:task:didCompleteWithError:检查错误的完整响应并调用此类通过初始化获得的回调闭包,以进一步继续执行结果数据:

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
    session.finishTasksAndInvalidate()

    if error != nil {
        var string: String?
        if errorString != nil {
            string = errorString
        } else {
            string = Helpers.NSURLErrorDomainErrorForCode(error!.code)
        }
        errorCallback(string!)
        return
    }

    if receivedData == nil {
        errorCallback("the query returned an empty result")
        return
    }

    var jsonError: NSError?
    let results: AnyObject! = NSJSONSerialization.JSONObjectWithData(receivedData!, options: NSJSONReadingOptions.AllowFragments, error: nil)

    if results == nil {
        errorCallback("the data returned was not valid JSON")
        return
    }

    let jsonParsed = JSONValue.fromObject(results)

    if let parsedAPIError = jsonParsed!["error"]?.string {
        errorCallback("API error: \(parsedAPIError)")
        return
    }

    callback(jsonParsed!, self.serverTime!)
}

0 个答案:

没有答案