WebScriptObject pass NSDictionary (ассоциативный массив / объект)

Я использую WebScriptObject вызывать методы JavaScript в WebView в Objective-C (OS X). Я хочу отправлять и получать объекты, такие как массивы и словари.

Я могу получить их так:

// 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"];

Когда я делаю вызов JavaScript, как window.external.log({key: "value"}); мой 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 ответ

Я почесал себе голову над лучшим способом обойти это ограничение, попробовал несколько реализаций на основе классов без особого успеха и в итоге нашел обходной путь, который сводится к следующему:

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" })]];
Другие вопросы по тегам