9

和这个玩得很开心。

我有一个超级简单的 Cocoa 应用程序,其中包含一个 WebView、一个在页面中定义的 WebScripting API,以及在该 API 上定义的一个 NSObject。当我打开调试器工具(在嵌入式 WebView 中)时,我可以在 JavaScript 窗口对象上看到 API,并且可以看到我在其上定义的“api”属性——但是当我调用 API 的“get”方法时,参数没有被序列化——当调用 Obj-C 方法时,参数丢失了。见下文,希望能说明:

在此处输入图像描述

我已经梳理了文档,我(显然)设置了适当的方法来公开需要公开的所有内容,并且我可以看到正在调用的方法。我必须有一些愚蠢的东西,但作为这个环境的相对新手,我没有看到它。

在此先感谢您的帮助!

4

3 回答 3

2

当您发送 -[NSUserDefaults registerDefaults:] 时,您是否在默认用户默认值中将 WebKitDeveloperExtras 设置为 YES?

于 2012-05-01T19:34:24.367 回答
1

根据您使用的 Xcode 版本,您可能会遇到已知错误。如果您在除最新版本之外的任何东西上使用 LLDB,它可能不会在调试器中为您提供正确的变量。在 Apple 解决问题之前,解决方案一直是使用 GDB 而不是 LLDB。但我认为他们在最新版本中解决了这个问题。我会更改调试器以使用 GDB 并查看您是否在 Xcode 中获得了正确的变量。(产品-> 编辑方案...-> 运行-> 调试器)。不过,我在 iOS 中遇到了这个问题,所以我不知道它对 OSX 的适用性。总之值得一试。

我最初在这里遇到了这个问题:https ://stackoverflow.com/a/9485349/1147934

于 2012-05-01T16:56:27.770 回答
0

我在应用程序的主线程中从存储在应用程序目录中的本地文件处理 javascript。我检查我正在执行的 js 函数的开始和结束标记,以及该函数是否包含变量。

希望这可以为您的问题提供一些好的想法。您还可以在 js 中发出警报,以查看在您运行应用程序时值是否正确发布(我相信您已经想到了这一点,但值得一提。)快乐编码!我希望这有帮助!

在 .h 文件中定义:

NSMutableString *processedCommand;
NSArray *commandArguments;

在 .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;
}
于 2012-05-08T17:10:30.707 回答