Skip to content

Instantly share code, notes, and snippets.

@matt-curtis
Last active August 22, 2019 07:13
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save matt-curtis/4d0a64048307fb54f874d665aac7e0e1 to your computer and use it in GitHub Desktop.
MOJavaScriptObject function execution
@import JavaScriptCore;
/// Retaining MOJavaScriptObject retains your JSContext/JSObject as well
@interface MOJavaScriptObject : NSObject
@property (readonly) JSObjectRef JSObject;
@property (readonly) JSContextRef JSContext;
@end
@implementation MOJavaScriptObject ()
- (JSValue*) callWithArguments:(NSArray*)argumentsArray {
JSContext *context = [JSContext contextWithJSGlobalContextRef:(JSGlobalContextRef)self.JSContext];
JSValue *function = [JSValue valueWithJSValueRef:self.JSObject inContext:context];
return [function callWithArguments:argumentsArray];
}
@end
@jamztang
Copy link

jamztang commented Mar 28, 2017

Thanks Matt, in additional to the original questions, I was trying to execute the code in background. I dispatched the operation in a global queue caused crash, even main thread caused crash. Would you happen to have some pointers for me on that?

// This works
- (void)runSomething:(MOJavaScriptObject *)closure {
    NSArray *args = @[@1, @3];
    JSContext *ctx = [JSContext contextWithJSGlobalContextRef:(JSGlobalContextRef)closure.JSContext];
    JSObjectRef fn = [closure JSObject];
    JSValue *value = [JSValue valueWithJSValueRef:fn inContext:ctx];
    JSValue *result = [value callWithArguments:args];   // result = 4

    NSLog(@"result %@", [result toString]);    // prints "result 4";
}


// This version is causing crash
- (void)runSomething:(MOJavaScriptObject *)closure  {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSArray *args = @[@1, @3];
        JSContext *ctx = [JSContext contextWithJSGlobalContextRef:(JSGlobalContextRef)closure.JSContext];
        JSObjectRef fn = [closure JSObject];
        JSValue *value = [JSValue valueWithJSValueRef:fn inContext:ctx];
        JSValue *result = [value callWithArguments:args];       // cause crash here

        NSLog(@"result %@", [result toString]);
    });
}

@nikogu
Copy link

nikogu commented Apr 4, 2018

@jamztang can you paste your closure code witch is how you trigger the runSomething method.

@websiddu
Copy link

@jamztang I'm trying to do the exact same thing. I was not able to get this working. Do you mind sharing a full example?

What functions you expose in cocoascript?
And how do you call them from the framework code?

@matt-curtis
Copy link
Author

For anyone else who finds this gist and has the same questions as @websiddu and @nikogu:

The problem in James's case was that his JSContext was being released by Sketch before the function could execute. The solution was to use coscript.setShouldKeepAround(true) to prevent Sketch from releasing the context early.

Copy link

ghost commented Aug 22, 2019

@jamztang can you paste your closure code witch is how you trigger the runSomething method.

fn1(a, b) { return a + b; }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment