2012-02-08 1 views
5

In un'app iOS, sto eseguendo uno script abbastanza grande su un UIWebView utilizzando stringByEvaluatingJavaScriptFromString (grande in termini di lunghezza della stringa javascript). C'è una breve pausa dopo aver chiamato il javascript facendo sì che altri elementi sullo schermo si bloccino per un momento.UIWebView stringByEvaluatingJavaScriptFromString in background

L'inserimento della chiamata javascript in una funzione chiamata in background con self performSelectorInBackground interrompe l'applicazione. C'è un modo sicuro per chiamare eseguire questo su un thread in background o altrimenti impedire all'interfaccia di sospendere?

risposta

0

Si potrebbe provare a mettere quella chiamata in una NSOperation. Poiché stai lavorando con un elemento dell'interfaccia utente, assicurati di utilizzare [NOMEperationQueue mainQueue].

+0

Come sarà di aiuto? –

2

Tutto ciò che si fa con un UIWebView deve essere fatto sul thread principale. È un elemento dell'interfaccia utente, ecco perché performSelectorInBackground interrompe la tua app.

3

No, Webviews e il motore JavaScript Webkit sono entrambi a thread singolo e non possono essere utilizzati su thread in background.

Una soluzione migliore è quella di dividere il vostro JavaScript in blocchi di esecuzione discreti e pipeline di loro utilizzando un timer JavaScript, come questo (codice JS, non Obj-C):

var i = 0; 
var operation = function() { 

    switch (i) { 
    case 0: 
     //do first part of code 
     break; 
    case 1: 
     //do second part of code 
     break; 
    case 2: 
     //do third part of code 
     break; 
    etc... 
    } 

    //prepare to execute next block 
    i++; 
    if (i < TOTAL_PARTS) { 
     setTimeout(operation, 0); 
    } 
}; 
operation(); 

che impediscono lo script da bloccando l'interazione dell'utente mentre viene eseguito

+0

Grazie. Questo risolve metà del problema ed è anche un po 'più del necessario. Semplicemente chiamando la funzione che fa tutto il lavoro con un breve timer, la pausa diventa molto più breve. Se ho capito bene, una volta eseguito lo script nella funzione 'stringByEvaluatingJavaScriptFromString', il thread principale può continuare in modo che la funzione chiamata dal timer js possa funzionare indipendentemente. C'è ancora una piccola pausa dal chiamare 'stringByEvaluatingJavaScriptFromString' con una stringa grande. Forse qualcosa come questo approccio sul lato obj-c potrebbe alleviare quello. –

+0

Invece di passare l'intero script come una stringa, è possibile aggiungerlo come tag di script all'html per la pagina e quindi attivarlo semplicemente chiamando una funzione con stringByEvaluatingJavaScriptFromString. –

+0

Sembra avere lo stesso miglioramento, ma non ancora il 100%. –

3

Bene, stavo facendo la stessa cosa. Ho dovuto eseguire una richiesta sincrona di Ajax che stava congelando la mia interfaccia utente. Ecco come ho risolto:

__block NSString *message; 
    dispatch_queue_t q = dispatch_queue_create("sign up Q", NULL); 
    dispatch_async(q, ^{ 
     NSString *function = [[NSString alloc] initWithFormat: @"signup(\'%@\',\'%@\',\'%@\')",self.email.text,self.password.text,self.name.text]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:function]; 
      NSLog(@"%@",result); 

      if ([result isEqualToString:@"1"]) { 
       message = [NSString stringWithFormat:@"Welcome %@",self.name.text]; 
       [self.activityIndicator stopAnimating]; 
       [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
      } 

      else { 
       message = [NSString stringWithFormat:@"%@ is a registered user",self.name.text]; 
       [self.activityIndicator stopAnimating]; 
       [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
      } 

      UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Message" message:message delegate:self cancelButtonTitle:@"Okay" otherButtonTitles: nil]; 
      [alertView show]; 
     }); 
    }); 

La logica è semplice. Vai a un nuovo thread, e dall'interno di questo, invia alla coda principale e poi fai il JS funziona e tutto ha funzionato come un fascino per me ...