2009-10-16 4 views
16

Je travaille sur une application pour iPhone depuis quelques semaines maintenant et l'une des fonctionnalités antérieures que j'ai ajouté était un UIWebView qui a chargé les sujets de la page Wikipedia contextuels sensibles. C'était assez trivial à mettre en œuvre et fonctionne bien depuis un certain temps.Quelqu'un a-t-il trouvé que UIWebView échoue pour certaines URL?

Aujourd'hui, j'ai trouvé que la fonctionnalité avait de façon inattendue cessé de fonctionner. J'avais tripoté autour du périmètre de ce morceau de code et supposé initialement que j'avais cassé quelque chose.

J'ai vérifié tous les endroits évidents, mes urls, était le UIWebView encore accroché dans le XIB etc. Je n'ai trouvé aucun problème.

Aller plus loin, je coincé une erreur de manipulation sur mon UIWebViewDelegatedidFailLoadWithError et trouvé que je recevais une erreur -999:

NSURLErrorCancelled

Returned when an asynchronous load is canceled.

A Web Kit framework delegate will receive this error when it performs a cancel operation on a loading resource. Note that an NSURLConnection or NSURLDownload delegate will not receive this error if the download is canceled.

Alors cela sonne comme faire une nouvelle demande (ou annulation) avant l'original a fini. Je vérifie mon code pour quelque chose comme ça et viens vide. Donc je suis entré dans ma spirale descendante habituelle de la paranoïa et supposé que Wikipédia bloquait les demandes basées sur UAgent ou quelque chose et a continué quelque chose de chasse à l'oie sauvage essayant de me frayer un chemin vers un endroit heureux. Ces tentatives n'ont pas réussi et finalement la santé mentale a prévalu. J'ai créé un script python simple pour imiter la requête HTTP que je faisais de mon APP dans le simulateur, pour voir ce que Wikipédia renvoyait:

string = "GET /wiki/Franklin_D._Roosevelt HTTP/1.1\r\nHost: en.wikipedia.org\r\nUser-Agent: test\r\nReferer: http://en.wikipedia.org/wiki/Franklin_D._Roosevelt\r\nAccept: */*\r\nAccept-Language: en-us\r\n_Accept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\n\r\n" 
import socket 
s = socket.socket() 
s.connect(("en.wikipedia.org",80)) 
s.send(string) 
x = s.recv (1000) 
while (x): 
    print x 
    x = s.recv (1000) 

Alors je cours ce gars-là et découvrir que Wikipedia est très bien vouloir rendre mon données rapidement et complètement. Alors, quoi de neuf? Chinks a commencé à apparaître dans mon actuelle armure paranoïaque "C'est toujours de ma faute" et je décide de vérifier si d'autres applications iPhone peuvent afficher ces URL. Je poste un tweet avec une URL ironiquement amusante (je suis facilement amusé) et vérifie si Tweetie peut voir l'URL. Ça ne peut pas.

Un ami l'essaye dans Twitterific. Même problème. Fonctionne bien dans Safari et l'application Wikipedia, mais il semble que les applications iPhone utilisant un standard UIWebView ont des problèmes avec les pages Wikipedia.

Juste pour être tout à fait certain qu'il n'y a pas d'autres variables, j'ai créé un simple test app avec juste un UIWebView qui charge jusqu'à http://en.wikipedia.com, il échoue avec la même erreur (ajouté que le code à la fin).

Alors, qu'en pensez-vous? Est-ce juste un bug UIWebView? Les Apple Gronks savent ce qui se passe ici?

Ai-je manqué quelque chose de complètement évident et je suis encore une fois assis dans le train pour travailler sans mon pantalon?

Dans l'attente d'entendre ce que vous pensez. Gardez à l'esprit, cela fonctionnait bien hier.

Debrief (ou peut-être nécropsie est plus approprié):

Merci Duncan pour la solution et une description assez claire de ce qui se passe ici.

On dirait que la raison pour laquelle j'ai vu à l'origine de l'erreur, quand je n'appliquait pas la didFailLoadWithError méthode déléguée du tout, est que le comportement par défaut de cette méthode est apparemment pour effacer le UIWebView et par conséquent tuer la demande . Lorsque j'ai ajouté ma mise en œuvre pour découvrir ce qui se passait, j'ai enfoncé un peu de code pour écrire l'erreur à la vue et, comme Duncan le fait remarquer, c'est ce qui m'a donné.

On dirait une solution assez horrible pour ignorer les codes d'erreur -999 dans le rappel, mais je vais bien avec du ruban adhésif.

J'ai essayé un certain nombre d'applications pour tester si c'était un problème UIWebView (Tweetie, Twitteriffic etc ...) et ils avaient tous le problème. Il semble que cela pourrait être une surveillance assez commune pour les développeurs. Peut-être que Apple peut nettoyer cela dans la prochaine version.

Un autre point intéressant est que lorsque j'ai changé mes URL pour utiliser http://en.m.wikipedia.com au lieu de http://en.wikipedia.com, le problème est parti.

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 
- (void)viewDidLoad { 
    [super viewDidLoad]; 
    _webView = (UIWebView*)self.view; 
    _webView.delegate = self; 

    // load the url 

    // FAIL 
    //NSURL * newUrl = [[[NSURL alloc] initWithString:@"http://en.wikipedia.com"] autorelease]; 

    // OK 
    NSURL * newUrl = [[[NSURL alloc] initWithString:@"http://www.stackoverflow.com"] autorelease]; 

    NSURLRequest * newUrlRequest = [NSURLRequest requestWithURL:newUrl]; 
    [_webView loadRequest:newUrlRequest];          
} 

// delegate stuff 
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)req navigationType:(UIWebViewNavigationType)navigationType { return YES; } 
- (void)webViewDidStartLoad:(UIWebView *)wv 
    { 
    // starting the load, show the activity indicator in the status bar 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 
} 

- (void)webViewDidFinishLoad:(UIWebView *)webView 
{ 
    // finished loading, hide the activity indicator in the status bar 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
} 

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error 
{ 
    NSURLErrorDomain 
    // load error, hide the activity indicator in the status bar 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
    [_webView loadHTMLString:[[[NSString alloc] initWithFormat:@"Failed to load page %@", [error localizedDescription]] autorelease] baseURL:nil]; 
} 
+0

On dirait que vous avez fait votre recherche ici. Je suis convaincu. Je pense que vous nous feriez tous une faveur si vous deviez déposer un radar avec Apple. Assurez-vous d'inclure votre application de test lorsque vous le produisez. –

+0

Merci Matt. J'ai essayé le travail de Duncan et cela fonctionne effectivement autour du problème. Je me sens comme UIWebView se comporte mal, mais si cela fonctionne ... :) – RedBlueThing

+0

J'ai tweeté @atebits sur le bug et la dernière version de Tweetie2 a la solution :) – RedBlueThing

Répondre

17

On dirait qu'il ya une réponse ici:

How do I fix NSURLErrorDomain error -999 in iPhone 3.0 OS

qui renvoie à son tour:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/6280-uiwebview-didfailloadwitherror-how-get-errors-code-list.html

On dirait que vous avez besoin d'un hack comme celui-ci dans le webView: didFailLoadWithError: délégué:

if ([error code] != NSURLErrorCancelled) { 
    //show error alert, etc. 
} 

Essentiellement, le délégué reçoit un échec «annulé» (-999), qui pourrait provenir de javascript ou peut-être même d'un bogue UIWebView.

Avec votre code, le webview n'affiche rien parce que vous utilisez le même UIWebView pour afficher l'erreur. Si vous aviez juste noté l'erreur NSLog'd vous auriez vu un échec, mais alors la page aurait bien chargé, vous donnant un indice que l'échec est faux.