Can't JSExport an Objective-C Method With More Than One Parameter?

ios, javascriptcore, objective-c

Solution

Quickly perusing JSContext.h uncovers this gem:

// When a selector that takes one or more arguments is converted to a JavaScript
// property name, by default a property name will be generated by performing the
// following conversion:
//  - All colons are removed from the selector
//  - Any lowercase letter that had followed a colon will be capitalized.
// Under the default conversion a selector "doFoo:withBar:" will be exported as
// "doFooWithBar". The default conversion may be overriden using the JSExportAs
// macro, for example to export a method "doFoo:withBar:" as "doFoo":
//
//    @protocol MyClassJavaScriptMethods <JSExport>
//    JSExportAs(doFoo,
//    - (void)doFoo:(id)foo withBar:(id)bar
//    );
//    @end
//
// Note that the JSExport macro may only be applied to a selector that takes one
// or more argument.
#define JSExportAs(PropertyName, Selector) \
    @optional Selector __JS_EXPORT_AS__##PropertyName:(id)argument; @required Selector

Problem

Consider this: ``` @protocol FooExport <JSExport> - (void)method1:(NSString *)param1; - (void)method2:(NSString *)param1 param2:(NSString *)param2; @end @interface Foo : NSObject <FooExport> @end @implementation Foo - (void)method1:(NSString *)param1 { NSLog(@"method1"); } - (void)method2:(NSString *)param1 param2:(NSString *)param2 { NSLog(@"method2"); } @end { sContext = [[JSContext alloc] init]; if (sContext) { sContext[@"foo"] = [[Foo alloc] init]; [sContext evaluateScript:@"foo.method1(\"foo\");"]; // method1 is called [sContext evaluateScript:@"foo.method2(\"foo\", \"bar\");"]; // method2 is NOT called } } ``` method1 is called just fine but method2 is never called. If I change method2 as follows: ``` @protocol FooExport <JSExport> - (void)method1:(NSString *)param1; - (void)method2:(NSString *)param1; @end ``` method2 is now called via [sContext evaluateScript:@"foo.method2(\"foo\", \"bar\");"]; (and I have to dig out the second parameter via JSContext.currentArguments). Similarly, if I change method2 as follows: @protocol FooExport - (void)method1:(NSString *)param1; - (void)method2; @end method2 is again called via [sContext evaluateScript:@"foo.method2(\"foo\", \"bar\");"]; (and I have to dig out both parameters via JSContext.currentArguments). Is this by design? The drawback of JSContext.currentArguments is that I have to deal with JSValues rather than the already converted objective-C types.

Original source