WebScriptObject传递NSDictionary(关联数组/对象)

时间:2015-01-13 23:23:50

标签: javascript objective-c webview nsdictionary web-scripting

我正在使用a WebScriptObject在Objective-C(OS X)的WebView中调用JavaScript方法。我想发送和接收像数组和字典这样的对象。

我可以这样收到:

// JWJSBridge
+ (BOOL)isSelectorExpludedFromWebScript:(SEL)selector {
    if (selector == @selector(log:)) {
        return NO;
    }
    return YES;
}
+ (NSString *)webScriptNameForSelector:(SEL)selector {
    if (selector == @selector(log:)) {
        return @"log";
    }
    return nil;
}
- (void)log:(WebScriptObject *)object {
    NSLog(@"object: %@", [[object JSValue] toObject]);
}

此对象设置为JavaScript环境,如下所示:

WebScriptObject *windowObject = [[self webView] windowScriptObject];
[windowObject setValue:[[JWJSBridge alloc] init] forKey:@"external"];

然后,当我按window.external.log({key: "value"});进行JavaScript调用时,JWJSBridge将对象记录为NSDictionary

现在我也想以另一种方式实现它。为此我创建了一个像这样的JavaScript对象:

window.internal = {log = function(a) { console.log(a); }};

它与数组完美配合:

WebScriptObject *internal = [[self webView] valueForKey:@"internal"];
[internal callWebScriptMethod:@"log" withArguments:@[@[@"value", @"value"]]];

但是当我想发送字典时,这是不可能的:

[internal callWebScriptMethod:@"log" withArgument:@[@{@"key": @"value"}]];

知道我很遗憾地得到一个带有空对象ObjCRuntimeObject的控制台消息。显然,Objective C没有/无法将字典序列化为JavaScript对象。我可以找到的一小块文档(我在这里没有再找到它作为参考)告诉我它只适用于数组。

我向苹果公司提交了一份错误报告:19464522

为什么Objective-C API提供了将所有内容转换为对象形式JavaScript但不反之亦然的方法?!

必须有可能,所以我该如何做到这一点?

1 个答案:

答案 0 :(得分:0)

一直在试图解决这个限制的最佳方法,尝试了一些基于类的实现,但没有取得多大成功,最终得到了一个解决方法,可以归结为:

id dict = [internal evaluateWebScript:@"(function() { return { key: { key: 'VALUE' } }; })()"];
[internal callWebScriptMethod:@"log" withArguments:@[dict]];

这可以像这样包装(为简洁而省略错误处理):

static id jsDictionary(WebScriptObject *const webScript, NSDictionary *const dictionary)
{
  NSData *const data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil];
  NSString *const json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  return [webScript evaluateWebScript:[NSString stringWithFormat:@"(function() { return %@; })()", json]];
}

然后像这样使用:

[internal callWebScriptMethod:@"log" withArguments:@[jsDictionary(internal, @{ @"key": @"VALUE" })]];