Search code examples
javascriptobjective-cjavascriptcore

How to convert a javascript object into an NSDictionary using JavaScriptCore


Let's say I have a javascript file, javascript.js, with the following content.

window.fruitsAndVeggies = {
    name2CategoryMap: {
        "apple": "fruit",
        "carrot": "vegetable"
    }
}

Can anyone tell me the easiest way to get the contents of the Javascript object window.fruitsAndVeggies into an NSDictionary?

From various sources on the internet I've pieced together the following snippet, that creates a Javascript context, and then evaluates the javascript code in that context.

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 );

I'm confused as to what to do next. I need to use the contents of fruitsAndVeggies.name2CategoryMap in my objective-c code. What's the easiest way to access them? Is there a simple function I can call to load them into an objective-c dictionary?

Many thanks for your help.


Solution

  • Things have become a lot simpler since the new Objective-C interface in JavaScriptCore introduced with iOS 7. For an intro to this, see the WWDC 2013 session "Integrating JavaScript into Native Apps" session on Apple's developer network: https://developer.apple.com/videos/wwdc/2013/?id=615

    The code you need after evaluating the javascript resource file is:

        JSContext *context = [JSContext contextWithJSGlobalContextRef:ctx];
        NSDictionary *fruitsAndVeggiesDict = [context[@"window"][@"fruitsAndVeggies"][@"name2CategoryMap"] toObject];
    
        NSLog(@"name2CategoryMap['apple'] = %@", fruitsAndVeggiesDict[@"apple"]);
        NSLog(@"name2CategoryMap['carrot'] = %@", fruitsAndVeggiesDict[@"carrot"]);