Я не уверен, что сделка здесь, но функция:NSURLProtocol. requestIsCacheEquivalent никогда не называли
class func requestIsCacheEquivalent(a: NSURLRequest, toRequest b: NSURLRequest) -> Bool
никогда не вызывается в моем NSURLProtocol подкласса. Я даже видел случаи использования кэша (проверяется с использованием сетевого прокси и не видит никаких вызовов), но этот метод никогда не запускается. Я не понимаю, почему это так.
Проблема, которую я пытаюсь решить, заключается в том, что у меня есть запросы, для которых я хотел бы кэшировать данные, но у этих запросов есть параметр подписи, который отличается для каждого из них (вроде как nonce). Это делает так, что ключи кеша не совпадают, несмотря на эквивалентные данные.
Для перехода в явном подробно:
- Я огонь запрос с пользовательской подписи (как это:
www.example.com?param1=1¶m2=2&signature=1abcdefabc312093
) - Запрос возвращается с Etag
- Etag должен быть управляемый NSURLCache, но поскольку он считает, что другой запрос (
www.example.com?param1=1¶m2=2&signature=1abdabcda3359809823
) делается, это не беспокоит.
Я думал, что с помощью NSURLProtocol бы решить все мои проблемы, так как документы от Apple говорят:
class func requestIsCacheEquivalent(_ aRequest: NSURLRequest,
toRequest bRequest: NSURLRequest) -> Bool
ДА, если аКедиезЬ и BREQUEST эквивалентны для целей кэша, NO иначе. Запросы считаются эквивалентными для целей кеша, если и только если они будут обрабатываться по тому же протоколу и что протокол объявляет их эквивалентными после выполнения проверок, связанных с реализацией.
К сожалению, эта функция никогда не называется. Я не знаю, что может быть проблема ...
class WWURLProtocol : NSURLProtocol, NSURLSessionDataDelegate {
var dataTask: NSURLSessionDataTask?
var session: NSURLSession!
var trueRequest: NSURLRequest!
private lazy var netOpsQueue: NSOperationQueue! = NSOperationQueue()
private lazy var delegateOpsQueue: NSOperationQueue! = NSOperationQueue()
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
println("can init with request called")
return true
}
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
println("canonical request for request called")
return request
}
override class func requestIsCacheEquivalent(a: NSURLRequest, toRequest b: NSURLRequest) -> Bool {
// never ever called?!?
let cacheKeyA = a.allHTTPHeaderFields?["CacheKey"] as? String
let cacheKeyB = b.allHTTPHeaderFields?["CacheKey"] as? String
println("request is cache equivalent? \(cacheKeyA) == \(cacheKeyB)")
return cacheKeyA == cacheKeyB
}
override func startLoading() {
println("start loading")
let sharedSession = NSURLSession.sharedSession()
let config = sharedSession.configuration
config.URLCache = NSURLCache.sharedURLCache()
self.session = NSURLSession(configuration: config, delegate: self, delegateQueue: self.delegateOpsQueue)
dataTask = session.dataTaskWithRequest(request, nil)
dataTask?.resume()
}
override func stopLoading() {
println("stop loading")
dataTask?.cancel()
}
//SessionDelegate
func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
println("did become invalid with error")
client?.URLProtocol(self, didFailWithError: error!)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
println("did complete with error")
if error == nil {
client?.URLProtocolDidFinishLoading(self)
} else {
client?.URLProtocol(self, didFailWithError: error!)
}
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
println("did receive response")
client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .Allowed)
completionHandler(.Allow)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
println("did receive data called")
client?.URLProtocol(self, didLoadData: data)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: (NSCachedURLResponse!) -> Void) {
println("will cache response called")
client?.URLProtocol(self, cachedResponseIsValid: proposedResponse)
completionHandler(proposedResponse)
}
Я зарегистрировал протокол в моем приложении делегата следующим образом:
NSURLProtocol.registerClass(WWURLProtocol.self)
Я запуска протокола следующим образом:
@IBAction func requestData(endpointString: String) {
let url = NSURL(string: endpointString)
let request = NSMutableURLRequest(URL: url!)
var cacheKey = endpointString
request.setValue("\(endpointString)", forHTTPHeaderField: "CacheKey")
request.cachePolicy = .UseProtocolCachePolicy
NSURLConnection.sendAsynchronousRequest(request, queue: netOpsQueue) { (response, data, error) -> Void in
if data != nil {
println("succeeded with data:\(NSString(data: data, encoding: NSUTF8StringEncoding)))")
}
}
}