Как преобразовать объект javascript в NSDictionary с помощью JavaScriptCore
Предположим, у меня есть файл javascript, javascript.js
, со следующим содержимым.
window.fruitsAndVeggies = {
name2CategoryMap: {
"apple": "fruit",
"carrot": "vegetable"
}
}
Может ли кто-нибудь подсказать мне самый простой способ получить содержимое объекта Javascript window.fruitsAndVeggies
в NSDictionary?
JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); // create context
JSValueRef exception = JSValueMakeUndefined(ctx); // create object to hold exceptions
// Make a "window" object in the JS Context
JSStringRef makeWindowScript = JSStringCreateWithUTF8CString("var window = {}");
JSValueRef result = JSEvaluateScript( ctx, makeWindowScript, NULL, NULL, 0, &exception );
// load the javascript file into an NSString
NSBundle * bundle = [NSBundle bundleWithIdentifier:@"my.bundle"];
NSString *filePath = [bundle pathForResource:@"javascript" ofType:@"js"];
NSError *error;
NSString *stringFromFile = [[NSString alloc]
initWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error];
// convert NSString to a JSStringRef
CFStringRef cfString = (__bridge CFStringRef)stringFromFile;
JSStringRef jsString = JSStringCreateWithCFString(cfString);
// evaluate the javascript
JSEvaluateScript( ctx, jsString, NULL, NULL, 0, &exception );
Я не знаю, что делать дальше. Мне нужно использовать содержание fruitsAndVeggies.name2CategoryMap
в моей цели-c код. Какой самый простой способ получить к ним доступ? Есть ли простая функция, которую я могу вызвать, чтобы загрузить их в словарь objective-c?
Большое спасибо за вашу помощь.
2 ответа:
Все стало намного проще с тех пор, как новый интерфейс Objective-C в JavaScriptCore появился в iOS 7. Для вступления к этому смотрите сеанс WWDC 2013 "интеграция JavaScript в нативные приложения" в сети разработчиков Apple: https://developer.apple.com/videos/wwdc/2013/?id=615
Код, который вам нужен после оценки файла ресурсов javascript:
JSContext *context = [JSContext contextWithJSGlobalContextRef:ctx]; NSDictionary *fruitsAndVeggiesDict = [context[@"window"][@"fruitsAndVeggies"][@"name2CategoryMap"] toObject]; NSLog(@"name2CategoryMap['apple'] = %@", fruitsAndVeggiesDict[@"apple"]); NSLog(@"name2CategoryMap['carrot'] = %@", fruitsAndVeggiesDict[@"carrot"]);
Как я ни старался, я не мог придумать элегантный способ попасть
window.fruitsAndVeggies
в словарь. Лучшее, что я мог сделать,-это вручную запустить цикл, который повторяет объект javascript и добавляет каждую пару ключ/значение в словарь один за другим.Код приведен ниже. Предупреждаю: это некрасиво. Если у вас есть более сжатое решение, я весь внимание!
/* Make the dictionary. */ NSMutableDictionary *fruitsAndVeggiesDict = [NSMutableDictionary dictionary]; /* In the JS context, create a variable called "keys". Return the number of keys (keys.length). */ result = JSEvaluateScript( ctx, JSStringCreateWithUTF8CString("var keys = Object.keys(window.fruitsAndVeggies.name2CategoryMap); keys.length"), NULL, NULL, 0, &exception ); double numKeys = JSValueToNumber(ctx, result, &exception); /* Iterate over the keys; convert each key/value into a pair of NSStrings. */ for(int i = 0; i < numKeys; i++){ // get a key, save in keyStrNS NSString *getKeyStr = [NSString stringWithFormat:@"keys[%d]", i]; CFStringRef getKeyStrCF = (__bridge CFStringRef)getKeyStr; JSStringRef getKeyStrJS = JSStringCreateWithCFString(getKeyStrCF); JSValueRef key = JSEvaluateScript( ctx, getKeyStrJS, NULL, NULL, 0, &exception ); JSStringRef keyStrJS = JSValueToStringCopy(ctx, key, &exception); NSString *keyStrNS = (NSString *)JSStringCopyCFString( kCFAllocatorDefault, keyStrJS ); // get a value, save in valueStrNS NSString *getValueStr = [NSString stringWithFormat:@"window.fruitsAndVeggies.name2CategoryMap[\"%@\"]", keyStrNS]; CFStringRef getValueStrCF = (__bridge CFStringRef)getValueStr; JSStringRef getValueStrJS = JSStringCreateWithCFString(getValueStrCF); JSValueRef value = JSEvaluateScript( ctx, getValueStrJS, NULL, NULL, 0, &exception ); JSStringRef valueStrJS = JSValueToStringCopy(ctx, value, &exception); NSString *valueStrNS = (NSString *)JSStringCopyCFString( kCFAllocatorDefault, valueStrJS ); /* store the key and value in our dictionary */ [fruitsAndVeggiesDict setObject: valueStrNS forKey: keyStrNS]; /* and print them for good measure */ NSLog(@"key %@ has value %@",keyStrNS,valueStrNS); }
Вывод:
key apple has value fruit key carrot has value vegetable