Variable argument list to JavascriptCore block
Asked Answered
E

2

5

I'd like to define a function in the JavascriptCore context that takes a variable amount of arguments.

Something like this:

JSVirtualMachine* virtualMachine = [[JSVirtualMachine alloc] init];
JSContext* ctx = [[JSContext alloc] initWithVirtualMachine:virtualMachine];

ctx[@"func"] = ^(JSValue* value, ...){
    va_list args;
    va_start(args, value);
    for (JSValue *arg = value; arg != nil; arg = va_arg(args, JSValue*)) {
        NSLog( @"%@", arg);
    }
    va_end(args);
};

[ctx evaluateScript:@"func('arg1', 'arg2');"];

I believe that the JSC wrapper doesn't pass the second argument to the block, because iterating on va_list crashes after logging the first argument.

I also tried with the NSArray* convention, it doesn't work.

Is this possible in any way?

Exploitation answered 11/2, 2014 at 3:49 Comment(2)
I also tried to do this when defining a Objective-C console log handler that took multiple args, but could not get it going even using NSLogv. A messy approach - you could try serialising the args into a single arg via JSON then unpacking it in your Objective-C handler.Autogenous
Yeah that would be a last resort approach. There's actually a way to do it using the regular C API, with JSObjectMakeFunctionWithCallback, but I'd like to go away from that C interface so ARC can handle JS Value's memory.Exploitation
L
8

From JSContext.h:

// This method may be called from within an Objective-C block or method invoked
// as a callback from JavaScript to retrieve the callback's arguments, objects
// in the returned array are instances of JSValue. Outside of a callback from
// JavaScript this method will return nil.
+ (NSArray *)currentArguments;

Leading to the following:

ctx[@"func"] = ^{
    NSArray *args = [JSContext currentArguments];
    for (JSValue *arg in args) {
        NSLog( @"%@", arg);
    }
};

[ctx evaluateScript:@"func('arg1', 'arg2');"];
Linzy answered 13/4, 2014 at 1:33 Comment(1)
That's also a great way to get JSValue objects from arguments. Just figured out that getting JSValues as block arguments (like ctx[@"func"] = ^(JSValue* value){...}) leaks the passed values. It sounds like the block retains the value so, the context retains the block, the block retains the value, and the value retains the context.Morbidity
T
1

I like @erm410's answer, I had not seen the documentation on currentArguments.

Another approach I have taken is to pass a JSON object to an Objective-C NSDictonary. One benefit to this approach is that you have named arguments - though you are dealing with string literals that will need to be typed correctly between the call and the handler.

ctx[@"func"] = ^(NSDictionary *args) {
    NSLog(@"%@", args[@"arg1"];
};

[ctx evaluateScript:@"func({'arg1':'first','arg2':'second'})"];
Turgor answered 6/5, 2014 at 13:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.