DISCLAIMER: This is a long post, but could prove very valuable for those grappling with using the new ObjectiveC JavascriptCore framework and doing asynchronous coding between ObjC and JS.
Hi there, I'm super new to Objective C and am integrating a javascript communication library into my iOS app.
Anyway, I've been trying my hand at using the new ObjectiveC JavaScriptCore Framework introduced in iOS7. It's pretty awesome for the most part, though quite poorly documented so far.
It's really strange mixing language conventions, but also kind of liberating in some ways.
I should add that I am of course using ARC, so that helps a lot coming from the Javascript world. But I have a question that's pretty specific around memory use issues when moving between ObjectiveC and the JSContext callBacks. Like if I execute a function in Javascript that then does some asynchronous code, and then calls back to a defined ObjectiveC block, and then that calls a defined JS callback... I just want to make sure I'm doing it right (ie. not leaking memory some place)!
Just to do things proper (because I reference a the class self
to call the ObjectiveC callBacks I create a weakSelf
so it plays nice with ARC (referenced from question: capturing self strongly in this block is likely to lead to a retain cycle):
__unsafe_unretained typeof(self) weakSelf = self;
Now, say I have a JSContext
and add a function to it. I want this function to take a callBack function and call it with "Hello" as an argument as well as pass ANOTHER function as a callBack. ie.
// Add a new JSContext.
JSContext context = [[JSContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]];
// Add a function to the context. This function takes a callBack function and calls it back with "Hello"
[context evaluateScript: @"var functionA = function(callBack){
var aMessage = "Foo";
callBack(aMessage, function(message){
/* message should say: Foo Bar */
});
}" ];
// Note, if you try to copy this code, you will have to get rid of the returns in the JS script.
Okay, so we have our basic JS side of things. Now to add the ObjectiveC complexity. I'm going to add the first ObjectiveC CallBack block:
context[@"functionB"] = ^(NSString *theMessage, JSValue *theCallBack){
[weakSelf objCFunction:theMessage withCallBack:theCallBack];
};
In the same class all this is happening in I also have the method definition. This is the place that causes the most concern to me:
-(void)objCFunction:(NSString *)message withCallBack:(JSValue *)callBack
{
NSString *concatenatedString = [NSString stringWithFormat:@"%@%@", message, @"Bar"];
[callBack callWithArguments:@[concatenatedString]];
}
So when I call:
[context evaluateScript: @"functionA(functionB);" ];
It should pass through the chain, and it does exactly what I expect it to do.
My main concern is that I hope I'm not somehow capturing a JSValue somewhere along this chain that is then leaking out.
Any help in helping me understand how ARC/the JSMachine would manage this approach to calling callBacks fluidly between Objective C and Javascript, would be super valuable!
Also, I hope this question helps others out there who are experimenting with this framework.
Thanks!