2012-04-18 20 views
9

Mieć chwilę czasu z tym.Wywołanie kodu Obj-C z JavaScript przez konsolę: Argumenty zostają odrzucone?

Mam bardzo prostą aplikację Cocoa zawierającą jeden WebView, interfejs API WebScripting zdefiniowany na stronie i pojedynczy obiekt NSObject zdefiniowany w tym interfejsie API. Kiedy włączam narzędzia do debugowania (we wbudowanym WebView), widzę API w obiekcie okna JavaScript i widzę na nim moją właściwość "api", ale kiedy wywołuję metodę API "get", argumenty nie są serializowane - gdy wywoływana jest metoda Obj-C, brakuje argumentów. Zobacz poniżej, które miejmy nadzieję ilustruje:

enter image description here

Mam czesane przez docs, mam (podobno) ustawić odpowiednie metody, aby odsłonić wszystko, co musi być narażeni, i widzę metoda samopoczucie nazywa. Musi być coś głupiego, czego mi brakuje, ale jako względnie początkujący w tym środowisku, nie widzę tego.

Z góry dziękuję za pomoc!

+0

Co ciekawe, wygląda na to, kiedy nazywam te metody ze skryptu w obrębie strony obciążonej przez WebView, wszystko wygląda dobrze. Dopiero po wywołaniu metod JavaScript za pomocą narzędzi programistycznych argumenty zostają odrzucone. Ponownie, metody są wywoływane, punkty przerwania są trafiane (w Xcode), ale nie ma argumentów. Stumped. –

+0

Czy próbowałeś zmienić wejście get: (NSString *), aby uzyskać: (id) wejście i ustawienie punktu przerwania (nie NSLog) tylko po to, aby zobaczyć, czy coś się pojawi? – JoeCortopassi

+1

Czy możemy również zobaczyć niektóre z kodu javascript? – Sam

Odpowiedz

1

W zależności od używanej wersji Xcode może pojawić się znany błąd. Jeśli używasz LLDB na czymkolwiek poza najnowszą wersją, może to nie zapewniać odpowiednich zmiennych w debugerze. Rozwiązaniem było użycie GDB zamiast LLDB, dopóki Apple nie rozwiąże problemu. Ale myślę, że naprawili problem w najnowszej wersji. Zmodyfikuję debuggera, aby używał GDB i sprawdzam, czy otrzymujesz odpowiednie zmienne w Xcode. (Product-> Edit Scheme ...-> Run -> Debugger). Natknąłem się na ten problem w iOS, więc nie wiem, czy można go zastosować w systemie OSX. Warto spróbować mimo to.

początkowo natknął się na problem tutaj: https://stackoverflow.com/a/9485349/1147934

+0

Najokropniejsza rzecz, ale to też nie działa. Dzięki za sugestię. –

+0

Nie ma problemu, przepraszam, że to nie zadziałało. –

2

masz ustawione WebKitDeveloperExtras na yes w domyślnej wartości domyślnych użytkownika podczas wysyłania - [NSUserDefaults registerDefaults:]?

+0

Po prostu próbowałem tego, by być pewnym - żadnych kości. Argh! Dzieki za sugestie. –

+0

Dlaczego zostało to odrzucone? – JoeCortopassi

0

Przetwarzam javascript w głównym wątku mojej aplikacji z lokalnego pliku przechowywanego w katalogu aplikacji. Sprawdzam początkowe i końcowe tokeny dla funkcji js, które wykonuję i czy funkcja zawiera zmienną.

Mam nadzieję, że może to dać kilka dobrych pomysłów na Twój problem. Możesz także robić alerty w js, aby sprawdzić, czy wartości są publikowane poprawnie podczas uruchamiania aplikacji (jestem pewien, że już o tym pomyślałeś, ale warto o tym wspomnieć). Szczęśliwe kodowanie! Mam nadzieję, że to pomoże!

w pliku .h określić:

NSMutableString *processedCommand; 
NSArray *commandArguments; 

W pliku .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; 
} 
Powiązane problemy