NSURLProtocol n'est pas invité à charger après la réponse YES à canInitWithRequest

J'inscris une implémentation de NSURLProtocol pour faire un traitement personnalisé de certaines requêtes d'URL (je marque ces requêtes en définissant des propriétés sur celles-ci). Ces requests d'URL proviennent d'une méthode de chargement d'UIWebView.

  1. Créer une vue Web de l'interface user (première charge après le lancement)
  2. Charger du contenu
  3. Détruire la vue Web
  4. Créer une nouvelle vue Web (charges suivantes)
  5. Charger du contenu

Je vois un comportement significativement différent entre les étapes 2 et 5. Mon implémentation NSURLProtocol gère datatables mises en cache et est conçu pour gérer les requests. Si je ne détecte pas ma propriété dans une requête, j'effectue une seconde vérification pour une URL spécifique (pour le debugging). Dans les deux cas, canInitWithRequest renverra YES :

Première charge après le lancement:

 2014-10-15 11:37:11.403 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ebbb40> https://example.com/ 2014-10-15 11:37:11.404 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15dc8da0> https://example.com/ 2014-10-15 11:37:11.409 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ee5ef0> https://example.com/ 2014-10-15 11:37:11.409 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ee6240> https://example.com/ 2014-10-15 11:37:11.410 MYApp[5813:60b] MYURLProtocol initWithRequest:cachedResponse:client: Request: https://example.com/ 2014-10-15 11:37:11.411 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ee69d0> https://example.com/ 2014-10-15 11:37:11.415 MYApp[5813:9c07] MYURLProtocol startLoading Loading <0x15ee6240> https://example.com/ ... A bunch of loading of assets occurs (cached responses) ... 2014-10-15 11:37:12.497 MYApp[5813:60b] MyWebViewController webViewDidFinishLoad: Finished loading 

D'autres ont souligné qu'il y a plusieurs appels au protocole à propos du même actif, et ce n'est pas un problème, bien qu'il soit intéressant de noter que chaque fois qu'il est appelé avec un nouvel object, c'est le 4ème (sur 4) object cela est passé à startLoading . Pourtant, pas de réelles préoccupations ici.

Chargements subséquents:

 2014-10-15 11:11:27.466 MYApp[5782:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x1727c310> https://example.com/ 2014-10-15 11:11:27.467 MYApp[5782:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x145b1d90> https://example.com/ 2014-10-15 11:11:27.488 MYApp[5782:560f] MYURLProtocol canInitWithRequest: Matched URL in request: <0x17266060> https://example.com/ 2014-10-15 11:11:27.669 MYApp[5782:60b] MYWebViewController webViewDidFinishLoad: Finished loading 

C'est là que le comportement, à mon avis, est inattendu. Il semble que la propriété a été retirée de la requête par la troisième fois qu'elle est passée à canInitWithRequest , et même si nous répondons YES nous ne sums jamais réellement initiés – la page est simplement returnnée à l' UIWebView dans son intégralité, sans aucune requests d'actifs ultérieures. Voici à quoi ressemble la requête lorsqu'elle est créée:

 NSURLRequest *request = [NSURLRequest requestWithURL:myURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; [self.webView loadRequest:request]; 

Pourquoi, quand je dis que mon protocole peut traiter la request, n'a-t-on pas l'occasion de le faire? Je suppose que la réponse est dans l'implémentation de UIWebView lui-même. Des reflections sur comment contourner cela si je veux vraiment que mon protocole soit l'entité responsable du chargement?

J'ai été capable de contourner ce problème en mettant en cache le cache UIWebView, tout en ne cassant pas le NSURLCache.

  1. Ajoutez un paramètre unique aux parameters de requête de la requête d'origine. J'ai choisi 'key = 000000' où la valeur est zéro nombre random à six numbers.
  2. Dans le protocole, initWithRequest:cachedResponse:client la key dans canonicalRequestForRequest: et dans initWithRequest:cachedResponse:client

Mon code d'extraction ressemble à ceci (il y a peut-être une façon plus simple de supprimer le param, mais cela fonctionne):

 + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { NSURLRequest *canonicalRequest = request; BOOL myProtocolRequest = [[NSURLProtocol propertyForKey:kMYProtocolRequest inRequest:request] boolValue]; if (myProtocolRequest) { NSMutableURLRequest *mutableRequest = [request mutableCopyWorkaround]; NSSsortingng *originalURLSsortingng = mutableRequest.URL.absoluteSsortingng; NSSsortingng *regexSsortingng = [NSSsortingng ssortingngWithFormat:@"(?:[?&])(key=[[:digit:]]{%d}&*)", kMYKeyLength]; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexSsortingng options:0 error:0]; NSTextCheckingResult *result = [regex firstMatchInSsortingng:originalURLSsortingng options:0 range:NSMakeRange(0, originalURLSsortingng.length)]; if (result.numberOfRanges > 1) { NSRange keyRange = [result rangeAtIndex:1]; NSLog(@"Removing '%@' from request", [originalURLSsortingng subssortingngWithRange:keyRange]); NSSsortingng *replacementURLSsortingng = [originalURLSsortingng ssortingngByReplacingCharactersInRange:keyRange withSsortingng:@""]; mutableRequest.URL = [NSURL URLWithSsortingng:replacementURLSsortingng]; canonicalRequest = mutableRequest; } } return canonicalRequest; } 

Mon code de démarrage ressemble à ceci:

 - (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client { self = [super initWithRequest:[MYURLProtocol canonicalRequestForRequest:request] cachedResponse:cachedResponse client:client]; return self; } 

Je n'aime pas que je doive faire cela, mais j'obtiens finalement exactement le comportement que je veux. Espérons que ça aide quelqu'un là-bas.

 *** Way to clear the cache of webview ********** Follow this code: NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; for (NSHTTPCookie *cookie in [storage cookies]) { [storage deleteCookie:cookie]; } [[NSUserDefaults standardUserDefaults] synchronize];