2009-10-16 10 views
16

He estado trabajando en una aplicación para iPhone por un par de semanas y una de las características anteriores que agregué fue UIWebView que cargó temas sensibles al contexto de la página de Wikipedia. Esto fue bastante trivial de implementar y ha estado funcionando bien por un tiempo.¿Alguien ha encontrado que UIWebView falla para algunas URL?

Hoy, he encontrado que la funcionalidad ha dejado de funcionar inesperadamente. Había estado jugueteando en el perímetro de ese fragmento de código y en un principio asumí que había roto algo.

He comprobado todos los lugares obvios, mis direcciones URL, era el UIWebView todavía conectado en el XIB, etc. No he encontrado ningún problema.

Al investigar más, me quedé un poco de manipulación en mi UIWebViewDelegatedidFailLoadWithError de error y se encontró que estaba recibiendo un error -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.

Así que esto suena como hacer una nueva solicitud (o cancelación) antes el original ha terminado. Compruebo mi código para algo como esto y vengo vacío.

Así que entré en mi habitual espiral descendente de paranoia y asumí que Wikipedia estaba bloqueando solicitudes basadas en UAgent o algo así y me puse en una especie de búsqueda inútil intentando fingir mi camino de regreso a un lugar feliz. Estos intentos no tuvieron éxito y finalmente prevaleció la sensatez. He creado un simple script en Python para imitar la petición HTTP que estaba haciendo desde mi aplicación en el simulador, para ver lo que Wikipedia enviaba de vuelta:

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) 

Así que correr este tipo y descubren que Wikipedia está muy amablemente regresando a mi datos de manera rápida y completa. ¿Entonces qué está pasando?

Las grietas comenzaron a aparecer en todos mis armaduras presentes, paranoicas "Siempre es mi culpa" y decido verificar si otras aplicaciones de iPhone pueden ver estas URL. Publiqué un tweet con una URL irónicamente divertida (me divierte mucho) y verifico si Tweetie puede ver la URL. No puede.

Un amigo lo prueba en Twitterific. El mismo problema. Funciona bien en Safari y en la aplicación de Wikipedia, pero parece que las aplicaciones de iPhone que usan un estándar de pantano UIWebView tienen problemas con las páginas de Wikipedia.

sólo para estar completamente seguro de que no hay otras variables, creé una simple test app con sólo un UIWebView que carga hasta http://en.wikipedia.com, falla con el mismo error (añadido el código al final).

¿Qué piensan? ¿Es esto solo un error UIWebView? ¿Alguna gente de Apple sabe qué está pasando aquí?

¿Me he perdido algo totalmente obvio y una vez más estoy sentado en el tren para trabajar sin los pantalones puestos?

Esperamos escuchar lo que piensas. Tenga en cuenta, esto estaba funcionando bien ayer.

Debrief (o tal vez Post Mortem es más apropiado):

Gracias Duncan de la solución y una descripción bastante clara de lo que está pasando aquí.

Parece que la razón por la que inicialmente vi el error, cuando no estaba implementando el método didFailLoadWithError delegado en absoluto, era que el comportamiento predeterminado de ese método es aparentemente para despejar el UIWebView y por consiguiente matar a la solicitud . Cuando agregué mi implementación para averiguar qué estaba pasando, inserté un código para escribir el error en la vista y, como señala Duncan, esto es lo que me atrapó.

Parece una solución bastante horrible para ignorar los códigos de error -999 en la devolución de llamada, pero estoy de acuerdo con la cinta adhesiva.

Probé algunas aplicaciones para probar si se trataba de un problema de UIWebView (Tweetie, Twitteriffic, etc ...) y todas tenían el problema. Parece que esto podría ser un descuido bastante común para los desarrolladores. Tal vez Apple pueda limpiar esto en la próxima versión.

Otro punto interesante es que cuando cambié mis URL para usar http://en.m.wikipedia.com en lugar de http://en.wikipedia.com, el problema desapareció.

// 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

Parece que ya has hecho tu investigación aquí. Estoy convencido. Creo que nos harías un favor a todos si archivaras un radar con Apple. Asegúrese de incluir su aplicación de prueba cuando la presente. –

+0

Gracias Matt. Probé el trabajo de Duncan y realmente se soluciona el problema. Siento que UIWebView se está portando mal, pero si funciona ... :) – RedBlueThing

+0

He twitteado @atebits sobre el error y la última versión de Tweetie2 tiene la solución :) – RedBlueThing

Respuesta

17

Parece que hay una respuesta aquí:

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

que a su vez se refiere a:

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

Parece que necesita un corte como este en la web View: didFailLoadWithError: delegar:

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

En esencia, lo que sucede es que el delegado obtiene un error "cancelado" (-999), que puede originarse en javascript o incluso en un error de UIWebView.

Con su código, la vista web no muestra nada porque está utilizando el mismo UIWebView para mostrar el error. Si acabaras de iniciar NSLogar el error, habrías visto una falla, pero luego la página se habría cargado correctamente, dándote una pista de que la falla es falsa.

Cuestiones relacionadas