I need to create a native node module that listens to an objective-c OSX event, and triggers a callback to javascript every time it happens:
nativeAddon.listen(() => {
console.log('It works!')
})
The callback works when immediately called in the setUpCallback
function, but it doesn't fire from the objective-c observer block.
Here's what my main.mm file looks like
using namespace v8;
Local<Function> event_callback;
void setUpCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
// Store the callback to be used in the runCallback function
Local<Function> cb = Local<Function>::Cast(args[0]);
event_callback = cb;
// THIS WORKS
runCallback();
// Listen to a mac event and trigger the callback when it happens
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserverForName:NSWorkspaceActiveSpaceDidChangeNotification object:NULL queue:NULL usingBlock:^(NSNotification *note) {
// THIS DOESN'T WORK
runCallback();
}];
}
void runCallback() {
auto isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
Local<Context> context = isolate->GetCurrentContext();
Local<Value> argv[1] = { String::NewFromUtf8(isolate, "hello world", NewStringType::kNormal).ToLocalChecked() };
auto fn = Local<Function>::New(isolate, event_callback);
fn->Call(context, Null(isolate), 1, argv).ToLocalChecked();
}
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "listen", setUpCallback);
}
NODE_MODULE(addon, Initialize)
Any help would be greatly appreciated!
Try changing the type of event_callback
from Local<Function>
to Persistent<Function>
.
The lifetime of a Local
is tied to that of the HandleScope
it was created in. Once the HandleScope
goes out of scope (in your case, at the end of function setUpCallback
), all Locals created while it was active become invalid. If you need a handle that persists after the HandleScope
went away, you need to use a Persistent
. More details here: https://v8.dev/docs/embed#advanced-guide.