2015-01-19 3 views
2

Я не уверен, что сделка здесь, но функция:NSURLProtocol. requestIsCacheEquivalent никогда не называли

class func requestIsCacheEquivalent(a: NSURLRequest, toRequest b: NSURLRequest) -> Bool 

никогда не вызывается в моем NSURLProtocol подкласса. Я даже видел случаи использования кэша (проверяется с использованием сетевого прокси и не видит никаких вызовов), но этот метод никогда не запускается. Я не понимаю, почему это так.

Проблема, которую я пытаюсь решить, заключается в том, что у меня есть запросы, для которых я хотел бы кэшировать данные, но у этих запросов есть параметр подписи, который отличается для каждого из них (вроде как nonce). Это делает так, что ключи кеша не совпадают, несмотря на эквивалентные данные.

Для перехода в явном подробно:

  1. Я огонь запрос с пользовательской подписи (как это: www.example.com?param1=1&param2=2&signature=1abcdefabc312093)
  2. Запрос возвращается с Etag
  3. Etag должен быть управляемый NSURLCache, но поскольку он считает, что другой запрос (www.example.com?param1=1&param2=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)))") 
     } 
    } 

} 

ответ

0

Я думаю, что на практике система загрузки просто использует канонизируемый URL для целей кеша и выполняет прямое сравнение строк. Хотя я не уверен. Попробуйте добавить свой nonce, когда вы его canonicalize, в той или иной форме, которая легко удаляется/обнаруживается (в случае, если она уже существует).

0

Ваш код выглядит все правильно. Вы просто следуете документам Apple о URLProtocol. Вы можете попробовать использовать URLSession для NSURLConnection устарел в новой версии iOS. Удачи.

Смежные вопросы