Skip to content

Instantly share code, notes, and snippets.

@matt-curtis
Last active August 22, 2019 07:13
Show Gist options
  • Select an option

  • Save matt-curtis/4d0a64048307fb54f874d665aac7e0e1 to your computer and use it in GitHub Desktop.

Select an option

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

jamztang commented Mar 28, 2017

Copy link
Copy Markdown

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

nikogu commented Apr 4, 2018

Copy link
Copy Markdown

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

@websiddu

Copy link
Copy Markdown

@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
Copy Markdown
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.

ghost commented Aug 22, 2019

Copy link
Copy Markdown

@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