Objective c 通过控制台从JavaScript调用Obj-C代码:参数被丢弃?

Objective c 通过控制台从JavaScript调用Obj-C代码:参数被丢弃?,objective-c,macos,cocoa,webkit,Objective C,Macos,Cocoa,Webkit,和这个玩得很开心 我有一个超级简单的Cocoa应用程序,其中包含一个WebView、一个在页面中定义的WebScript API和一个在该API上定义的NSObject。当我打开调试器工具(在嵌入式WebView中)时,我可以看到JavaScript窗口对象上的API,我可以看到在该对象上定义的“API”属性——但是当我调用API的“get”方法时,参数没有被序列化——当调用Obj-C方法时,参数丢失。见下文,希望能说明: 我已经梳理了文档,我(显然)设置了适当的方法来公开所有需要公开的内容,

和这个玩得很开心

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

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


提前感谢您的帮助

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


我最初在这里遇到了一个问题:

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

我在我的应用程序的主线程中从存储在应用程序目录中的本地文件处理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;
}
//令牌
#定义kOpenToken@“”
//这个会扔
-(void)executeJScriptCommand:(NSString*)命令{
[self-performSelectorOnMainThread:@selector(executeThisCommand:)with object:aCommand和waitUntilDone:YES];
}
//这个会扔
-(NSString*)executeCommand:(NSString*)命令{
NSString*aCommand=[[[command stringByReplacingOccurrencesOfString:kOpenToken with string:@']
stringByReplacingOccurrencesOfString:kCloseToken with string:@“”]
stringbytrimmingleading和trailingwhitespaces];
if([aCommand hasPrefix:@“=”]))
{
//变量。获取值
[self-getVariableFromCommand:aCommand];
}
否则{
[自执行命令:命令];
}
NSString*returnValue=[NSString stringWithString:processedCommand];
self.processedCommand=nil;
self.commandArguments=nil;
返回值;
}
-(void)executeThisCommand:(NSString*)命令{
BOOL hasrerror=NO;
//明确的结果
self.processedCommand=nil;
self.commandArguments=nil;
BOOL isFromJS=否;
NSString*函数=nil;
NSMutableArray*commandParts=nil;
@试一试{
//首先,将命令分成几个部分,提取需要调用的函数和(可选)参数
commandParts=[[NSMutableArray alloc]initWithArray:[A命令组件通过字符串分离:@]:“]];
if([[commandParts objectAtIndex:0]小写]isEqualToString:@“js调用”]){
isFromJS=是;
[commandParts removeObjectAtIndex:0];
}
//获取我们的函数,参数
函数=[[commandParts对象索引:0]保留];
[commandParts removeObjectAtIndex:0];
如果([commandParts计数]>0){
如果(isFromJS==是){
NSString*参数=[[commandParts objectAtIndex:0]stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
如果([参数长度]>0){
self.commandArguments=[arguments JSONValue];
}
}
否则{
self.commandArguments=[NSArray arrayWithArray:commandParts];
}
}
//构建调用
SEL=NSSelectorFromString(函数);
if([自响应选择器:sel]){
[self-performSelectorOnMainThread:SELWithObject:nil waitUntilDone:YES];
//使用调用会导致SIGABORT,因为try/catch块未捕获异常。
//使用执行选择器修复了该问题(即,try/catch块现在正确捕获异常,如预期的那样)
}
否则{
[appDelegate buildNewExceptionWithName:@”和消息:[NSString stringWithFormat:@“对象不响应选择器%@”,函数];
}
}
@捕获(N例外*e){
hasError=是;
[self-updateErrorMessage:[NSString stringWithFormat:@“错误处理命令%@:%@”,一条命令,[e原因]];
}
@最后{
[功能释放];
[发布命令];
}
如果(hasError==是){
[appDelegate BuildNewException,名称:@“executeThisCommand”和消息:self.errorMessage];
}
}
//这可以返回零
-(NSString*)getQueryStringValue:(NSString*)名称{
NSString*returnValue=nil;
if(queryString!=nil){
returnValue=[queryString objectForKey:[name lowercaseString]];
}
返回值;
}

有趣的是,当我从WebView加载的页面中的脚本调用这些方法时,情况看起来还不错。只有当我使用开发人员工具调用JavaScript方法时,参数才会被删除。同样,方法被调用,断点被命中(在Xcode中),但没有参数。难住了。您是否尝试过将get:(NSString*)input更改为get:(id)input并设置一个断点(而不是NSLog)以查看是否遇到任何问题?我们可以看看一些javascript代码吗?该死的