5

JavascriptCore is a new framework supported in iOS7. We can use the JSExport protocol to expose parts of objc class to JavaScript.

In javascript, I tried to pass function as parameter. Just like this:

function getJsonCallback(json) {
        movie = JSON.parse(json)
        renderTemplate()
}
viewController.getJsonWithURLCallback("", getJsonCallback)

In my objc viewController, I defined my protocol:

@protocol FetchJsonForJS <JSExport>
 - (void)getJsonWithURL:(NSString *)URL
               callback:(void (^)(NSString *json))callback;
 - (void)getJsonWithURL:(NSString *)URL
         callbackScript:(NSString *)script;
@end

In javascript, viewController.getJsonWithURLCallbackScript works, however, viewController.getJsonWithURLCallback not work.

Is there any mistake that I used block in JSExport? Thx.

liaojinxing
  • 63
  • 1
  • 6

1 Answers1

7

The problem is you have defined the callback as an Objective-C block taking a NSString arg but javascript doesn't know what to do with this and produces an exception when you try to evaluate viewController.getJsonWithURLCallback("", getJsonCallback) - it thinks the type of the second parameter is 'undefined'

Instead you need to define the callback as a javascript function.

You can do this in Objective-C simply using JSValue.

For other readers out there, here's a complete working example (with exception handling):

TestHarnessViewController.h:

#import <UIKit/UIKit.h>
#import <JavaScriptCore/JavaScriptCore.h>

@protocol TestHarnessViewControllerExports <JSExport>
- (void)getJsonWithURL:(NSString *)URL callback:(JSValue *)callback;
@end

@interface TestHarnessViewController : UIViewController <TestHarnessViewControllerExports>
@end

TestHarnessViewController.m: (if using copy/paste, remove the newlines inside the evaluateScript - these were added for clarity):

#import "TestHarnessViewController.h"

@implementation TestHarnessViewController {
    JSContext *javascriptContext;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    javascriptContext  = [[JSContext alloc] init];
    javascriptContext[@"consoleLog"] = ^(NSString *message) {
        NSLog(@"Javascript log: %@",message);
    };
    javascriptContext[@"viewController"] = self;

    javascriptContext.exception = nil;
    [javascriptContext evaluateScript:@"
        function getJsonCallback(json) {
            consoleLog(\"getJsonCallback(\"+json+\") invoked.\");
            /* 
            movie = JSON.parse(json); 
            renderTemplate(); 
            */
        } 

        viewController.getJsonWithURLCallback(\"\", getJsonCallback);
    "];
    JSValue *e = javascriptContext.exception;
    if (e != nil && ![e isNull])
        NSLog(@"Javascript exception occurred %@", [e toString]);
}

- (void)getJsonWithURL:(NSString *)URL callback:(JSValue *)callback {
    NSString *json = @""; // Put JSON extract from URL here
    [callback callWithArguments:@[json]];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
Mike
  • 3,722
  • 1
  • 28
  • 41
  • do getJsonWithURLCallback(\"\", getJsonCallback) in javascript calls - (void)getJsonWithURL:(NSString *)URL callback:(JSValue *)callback ? I was having issue fro calling two parameterized function from javascript using JSContext please help. – jnix Apr 02 '14 at 04:33
  • @jnix - sorry I didn't understand your comment. Perhaps you should post a new question. – Mike Apr 04 '14 at 22:23
  • @Mike I was saying I was unable to call native objcC function with to parameters .For more detail you can see -http://stackoverflow.com/questions/22801909/calling-native-ios-method-with-two-parametres-from-uiwebview-using-jscontext quetion – jnix Apr 06 '14 at 08:11
  • 3
    @jnix - Your comment above didn't explain what problem you were running into (especially since the sample answer already worked for two parameters), but reading your other question I see you've already solved it - ObjC methods exposed via JSExport have altered names if multiple parameters are involved `objCMethod:withArgTwo:andArgThree:` becomes `objCMethodWithArgTwoAndArgThree()` in javascript. – Mike Apr 07 '14 at 01:32
  • It its true. I came to know after trying combinations:D thanks for replying. – jnix Apr 07 '14 at 05:59