我对使用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: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!)
}