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" })]];