2011-01-18 14 views
6

Sto cercando di eseguire alcuni Javascript sul contenuto all'interno di UIWebView. Forse la mia conoscenza del tempo di esecuzione Javascript è carente, ma io "m confuso circa il seguente esempio Vedere codice sorgente e commenti per i dettagli:.Conferma del comportamento di Javascript in una UIWebView

NSString *html = [NSString stringWithFormat:@"<html><head><script type='text/javascript'>var content='the initial content';function myFunc(){return 'value of content: ' + content;}myFunc();</script></head><body>Hello blank</body></html>"]; 
// I would expect after this call that the variable content exists, as well as the function myFunc() 
[self.webView loadHTMLString:html baseURL:nil]; 
// However, it appears not to. The following call returns nothing 
NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@"myFunc();"]; 
NSLog(@"result: %@", result); 

// Inserting the Javascript at this point seems to work as expected 
result = [self.webView stringByEvaluatingJavaScriptFromString:@"var content='the new content';function myFunc(){return 'value of content: ' + content;}myFunc();"]; 
NSLog(@"result: %@", result); 

// And calling myFunc() at this point is successful 
result = [self.webView stringByEvaluatingJavaScriptFromString:@"myFunc();"]; 
NSLog(@"result: %@", result); 

In sintesi, mi aspetterei che la variabile globale Javascript e la funzione ho creato . quando si carica il codice HTML sia disponibile a seguito javascript chiama Sorprendentemente, non sembra, e tutto javascript roba deve essere aggiunto in seguito è corretto

grazie per qualsiasi aiuto in anticipo

.?. - --- update ----- Dovrei aggiungere che self.view è una WebView in questo caso. rico mettendo il tag script sia nella testa che nel corpo del documento HTML, senza alcun cambiamento nel comportamento.

+0

Anche questo mi sorprende. Devo chiedere (non correlato alla domanda), perché chiami myFunc() dopo averlo dichiarato? – donkim

+0

Ah, questo era solo per verificare se qualcosa è successo. Non dovrebbe essere lì. Toglierlo non fa nulla. –

risposta

3

di McLin è corretta in quanto UIWebView esegue i carichi sullo sfondo. Se tutto quello che stai caricando è semplice html e nessun tag ha src = "..." digita il contenuto allora puoi essere ragionevolmente sicuro che webViewDidFinishLoad (metodo di protocollo UIWebViewDelegate) verrà chiamato una sola volta e che puoi eseguire il tuo javascript in quel delegato metodo.

Tuttavia, UIWebView, dopo aver caricato l'iniziale HTML di avvio di caricamento di qualsiasi immagine, verrà chiamato javascript, audio, video, ecc. E webViewDidFinishLoad al completamento di ciascuno di questi carichi successivi. Penso che se guardi la barra di avanzamento di Safari sul tuo iPhone, puoi vedere questo comportamento. La barra di avanzamento va avanti a metà strada dopo che la pagina iniziale si carica e poi marcia un po 'alla volta come le immagini o cosa hai caricato.

Ho provato un paio di tecniche per eseguire javascript al termine del caricamento della pagina. Più facile è avere webViewDidFinishLoad eseguire un altro selettore dopo un breve ritardo e controllare la proprietà di caricamento di webView. Stai correndo un po 'di rischio in quanto portiamo "timing" e "discussioni" insieme, ma hey ... se vuoi che sia facile (cioè che sia).

-(void) checkIfLoadDone:(UIWebView *) webView { 
    if (webView.loading) { return; } 
    // run your javascript here 
} 

-(void) webViewDidFinishLoad:(UIWebView *) webView { 
    [NSObject cancelPreviousPerformRequestsWithTarget:self 
              selector:@selector(checkIfLoadDone:) 
              object:webView]; 
    [self performSelector:@selector(checkIfLoadDone:) 
      withObject:webView 
      afterDelay:0.5]; 
} 

-(void) webViewDidStartLoad:(UIWebView *)webView { 
    [NSObject cancelPreviousPerformRequestsWithTarget:self 
              selector:@selector(checkIfLoadDone:) 
              object:webView]; 
} 

- (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 
    // ooops ... probably should deal with the error, but lets just run checkIfLoadDone 
    [NSObject cancelPreviousPerformRequestsWithTarget:self 
              selector:@selector(checkIfLoadDone:) 
              object:webView]; 
    [self performSelector:@selector(checkIfLoadDone:) 
      withObject:webView 
      afterDelay:0.5]; 
} 

Una tecnica più complessa consiste nel tenere traccia dei carichi singolarmente e mantenere un contatore. Quando il contatore torna a 0, puoi eseguire javascript. In tal caso si vorrà per implementare il metodo delegato per

- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 
    if (navigationType != UIWebViewNavigationTypeOther) { 
    self.outStandingLoads = 0; 
    } 
    return YES; 
} 

Ora potete avere webViewDidStartLoad: outStandingLoads incremento e hanno webViewDidFinishLoad: e WebView: didFailLoadWithError: decremento e verificare outStandingLoads. Userei una proprietà atomica NSInteger per outStandingLoads in tutto il codice per affrontare il potenziale per il fatto che ci sia più di un thread che fa il caricamento.

Penso che entrambi i metodi funzionino abbastanza bene. Ho scelto quest'ultimo approccio, ma solo perché avevo bisogno di affrontare altri problemi nelle chiamate webViewDelegate. Ho deciso di estendere UIWebView e renderlo il proprio delegato in cui la mia estensione implementava i metodi delegati.Quindi utilizzo il modello NSNotification per inviare notifiche come "WebPageLoadBegan" e "WebPageLoadComplete" per comunicare con il mio codice di interfaccia utente. Mi è sembrato un modello più semplice quando lavoravo con due diversi set di codice UI ... l'iPad e l'iPhone.

Spero che questo aiuti.

+0

Questa è probabilmente la migliore descrizione del processo di caricamento di webView spesso misterioso. L'API è enorme, sì, ma la documentazione di Apple è odiosamente spartana/focalizzata solo su cose che "vogliono che tu faccia". Detto questo ... In base alla tua risposta - non sarebbe possibile guardare semplicemente "WebViewProgressFinishedNotification" per "Sì, sono sicuro" rispondi "è questo" m-fer caricato? ".. aka, posso FINALMENTE, effettivamente eseguo questo script _relabilmente? _ –

1

UIWebView non ha completato il caricamento.

Quando si chiama [self.webView loadHTMLString:html baseURL:nil]; non lo carica immediatamente. Avvia un thread per farlo in modo asincrono, quindi non viene caricato durante la valutazione del JS.

Fai delegato il controller di vista della UIWebView e poi valutare le vostre JS in risposta -(void)webViewDidFinishLoad:(UIWebView *)webView

+0

Interessante, ha senso. Ci proveremo domani. –

Problemi correlati