10.6 Blocks as arguments to methods.

15 views
Skip to first unread message

Gus Mueller

unread,
Sep 12, 2010, 5:00:45 PM9/12/10
to JSCocoa
Let's say I wanted to do something like this:

------------
var f = function(err) {
print("Hello from a jsfunction");
};

var objcBlock = JSTestBlocks.newErrorBlockForJSFunction_(f);

print(objcBlock);

JSTestBlocks.testFunction_(objcBlock);
------------

Where newErrorBlockForJSFunction just returns an objc block that calls the js function:

------------
@interface JSTestBlocks : NSObject { } @end

@implementation JSTestBlocks

+ (id)newErrorBlockForJSFunction:(JSValueRefAndContextRef)callbackFunction {
void (^theBlock)(NSError *) = ^(NSError *err) {
id jsc = [JSCocoa controllerFromContext:callbackFunction.ctx];
[jsc callJSFunction:callbackFunction.value withArguments:[NSArray arrayWithObjects:err, nil]];
};

return [theBlock copy];
}

+ (void)testFunction:(void (^)(NSError *))theBlock {
theBlock(nil);
}

@end
------------


JSCocoa ends up complaining about having -3 arguments, when 1 is required. Any idea what needs to be changed to allow this? Is it the type encodings? Something else?

thanks,

-gus

--

August 'Gus' Mueller
Flying Meat Inc.
http://flyingmeat.com/

Patrick Geiller

unread,
Sep 25, 2010, 3:53:31 AM9/25/10
to jsc...@googlegroups.com

Fixed. Blocks are encoded as '@?', JSCocoa did not support those.

Regarding the callbackFunction : the context you get is not the main context, but more like a call stack, therefore it will be invalid once control returns from your block creation. You need to get the main JavascriptCore context and maybe protect the function itself - if it has no name in the main scope , or is not part of an object itself in the main scope, it will be collected. (Giving an anonymous function to JSTestBlocks. newErrorBlockForJSFunction_(function () { .... handler code ...}) will eventually crash if not protected)


I've added your code to TestsRunner's ApplicationController :

+ (id)newErrorBlockForJSFunction:(JSValueRefAndContextRef)callbackFunction {

JSContextRef mainContext = [[JSCocoa controllerFromContext:callbackFunction.ctx] ctx];

// Protect function using the main context (JavascriptCore creates a new context every time it enters a function)
// (This is not needed if the function has a name in the main scope or is stored in an object or array stored in the main scope) 
JSValueProtect(mainContext, callbackFunction.value);


   void (^theBlock)(NSError *) = ^(NSError *err) {
       [[JSCocoa controllerFromContext:mainContext] callJSFunction:callbackFunction.value withArguments:[NSArray arrayWithObjects:err, nil]];
   };

   return [theBlock copy];
}



Gus Mueller

unread,
Sep 26, 2010, 7:47:08 PM9/26/10
to jsc...@googlegroups.com
On Sep 25, 2010, at 12:53 AM, Patrick Geiller wrote:

> Fixed. Blocks are encoded as '@?', JSCocoa did not support those.

Awesome- thanks! Verified that it works too!

> Regarding the callbackFunction : the context you get is not the main
> context, but more like a call stack, therefore it will be invalid once
> control returns from your block creation.

<snip>

Thanks for clarifying that as well. Tried it out, and it works. This will be great for some tests I use.

Reply all
Reply to author
Forward
0 new messages