2012-04-18 10 views
9

Avere un diavolo di tempo con questo.Chiamare il codice Obj-C da JavaScript tramite Console: gli argomenti vengono ignorati?

Ho una super-semplice applicazione Cocoa contenente una WebView, un'API WebScripting definita nella pagina e un singolo NSObject definito su tale API. Quando accendo gli strumenti del debugger (nel WebView incorporato), posso vedere l'API sull'oggetto della finestra JavaScript, e posso vedere la mia proprietà "api" definita su quello - ma quando chiamo il metodo "get" dell'API, gli argomenti non vengono serializzati - quando viene chiamato il metodo Obj-C, mancano gli argomenti. Vedi sotto, che illustra spera:

enter image description here

ho pettinato attraverso i documenti, ho (apparentemente) impostare i metodi appropriati per esporre tutto ciò che deve essere esposto, e posso vedere il metodo dell'essere chiamato. Deve esserci qualcosa di stupido che mi manca, ma come novellino di questo ambiente, non lo vedo.

Grazie in anticipo per il vostro aiuto!

+0

È interessante notare, sembra che quando chiamo questi metodi da script all'interno di una pagina caricata dal WebView, le cose sembrano a posto. È solo quando invoco i metodi JavaScript con gli strumenti di sviluppo che gli argomenti vengono eliminati. Di nuovo, i metodi vengono chiamati, i punti di interruzione vengono colpiti (in Xcode), ma non gli argomenti. Perplesso. –

+0

Avete provato a cambiare ottenere: (NSString *) input per ottenere: input (id) e impostazione di un punto di interruzione (non NSLog) solo per vedere se qualcosa sta attraversando? – JoeCortopassi

+1

Possiamo vedere anche parte del codice javascript? – Sam

risposta

1

A seconda della versione di Xcode in uso, è possibile che si verifichi un errore noto. Se stai usando LLDB su qualsiasi cosa tranne la versione più recente, potrebbe non darti le variabili giuste nel debugger. La soluzione è stata quella di utilizzare GDB anziché LLDB fino a quando Apple non risolve il problema. Ma penso che abbiano risolto il problema nell'ultima versione. Vorrei cambiare il debugger per usare GDB e vedere se stai ottenendo le variabili giuste in Xcode. (Prodotto-> Modifica schema ...-> Esegui -> Debugger). Mi sono imbattuto in questo problema in iOS, quindi, quindi non conosco la sua applicabilità a OSX. Vale la pena provare comunque.

Originariamente ho sono imbattuto nel problema qui: https://stackoverflow.com/a/9485349/1147934

+0

La cosa più dannatamente, ma non sembra funzionare. Grazie per il suggerimento, però. –

+0

Nessun problema, mi dispiace non ha funzionato. –

2

Hai impostato WebKitDeveloperExtras yes nel predefinite predefinite dall'utente quando si invia - [NSUserDefaults registerDefaults:]?

+0

Ho appena provato questo per essere sicuro - niente da fare. Argh! Grazie per il suggerimento. –

+0

Perché è stato downvoted? – JoeCortopassi

0

Elaborazione javascript nel thread principale della mia app da un file locale archiviato nella directory apps. Controllo i token di inizio e fine per le funzioni js che sto eseguendo e se la funzione contiene una variabile.

Speriamo che questo possa darvi alcune buone idee per il vostro problema. Potresti anche fare degli avvisi nella js per vedere se i valori vengono pubblicati correttamente mentre esegui l'app (sono sicuro che ci hai già pensato, ma vale la pena menzionarli.) Buona programmazione! Spero che aiuti!

nel file .h definiscono:

NSMutableString *processedCommand; 
NSArray *commandArguments; 

Nel file .m:

// tokens 
#define kOpenToken @"<%%" 
#define kCloseToken @"%%>" 

// this will throw 
-(void)executeJScriptCommand:(NSString *)aCommand { 

[self performSelectorOnMainThread:@selector(executeThisCommand:) withObject:aCommand waitUntilDone:YES]; 
} 

// this will throw 
-(NSString *)executeCommand:(NSString *)command { 

NSString *aCommand = [[[command stringByReplacingOccurrencesOfString:kOpenToken withString:@""] 
         stringByReplacingOccurrencesOfString:kCloseToken withString:@""] 
         stringByTrimmingLeadingAndTrailingWhitespaces]; 

if ([aCommand hasPrefix:@"="]) 
{ 
    // variable. get value 
    [self getVariableFromCommand:aCommand]; 
} 
else { 
    [self executeThisCommand:aCommand]; 
} 

NSString *returnValue = [NSString stringWithString:processedCommand]; 

self.processedCommand = nil; 
self.commandArguments = nil; 

return returnValue; 
} 

-(void)executeThisCommand:(NSString *)aCommand { 

BOOL hasError = NO; 

// clear result 
self.processedCommand = nil; 
self.commandArguments = nil; 

BOOL isFromJS = NO; 
NSString *function = nil; 
NSMutableArray *commandParts = nil; 

@try { 
    // first, break the command into its parts and extract the function that needs to be called, and the (optional) arguments 
    commandParts = [[NSMutableArray alloc] initWithArray:[aCommand componentsSeparatedByString:@":"]]; 
    if ([[[commandParts objectAtIndex:0] lowercaseString] isEqualToString:@"js-call"]) { 
     isFromJS = YES; 
     [commandParts removeObjectAtIndex:0]; 
    } 

    // get our function, arguments 
    function = [[commandParts objectAtIndex:0] retain]; 
    [commandParts removeObjectAtIndex:0]; 

    if ([commandParts count] > 0){ 
     if (isFromJS == YES) { 
      NSString *arguments = [[commandParts objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
      if ([arguments length] > 0) { 
       self.commandArguments = [arguments JSONValue]; 
      } 
     } 
     else { 
      self.commandArguments = [NSArray arrayWithArray:commandParts]; 
     } 
    } 

    // build invoke 
    SEL sel = NSSelectorFromString(function); 

    if ([self respondsToSelector:sel]) { 

     [self performSelectorOnMainThread:sel withObject:nil waitUntilDone:YES]; 

     // using invocation causes a SIGABORT because the try/catch block was not catching the exception. 
     // using perform selector fixed the problem (i.e., the try/catch block now correctly catches the exception, as expected) 

    } 
    else { 
     [appDelegate buildNewExceptionWithName:@"" andMessage:[NSString stringWithFormat:@"Object does not respond to selector %@", function]]; 
    } 

} 
@catch (NSException * e) { 
    hasError = YES; 
    [self updateErrorMessage:[NSString stringWithFormat:@"Error processing command %@: %@", aCommand, [e reason]]]; 
} 
@finally { 
    [function release]; 
    [commandParts release]; 
} 

if (hasError == YES) { 
    [appDelegate buildNewExceptionWithName:@"executeThisCommand" andMessage:self.errorMessage]; 
} 
} 

// this can return nil 
-(NSString *)getQueryStringValue:(NSString *)name { 

NSString *returnValue = nil; 
if (queryString != nil) { 
    returnValue = [queryString objectForKey:[name lowercaseString]]; 
} 

return returnValue; 
} 
Problemi correlati