StevenH
November 5, 2016, 1:21pm
#1
Hi there,
i have a pure ObjectC app written with Xcode.
No i’d like to execute an applescript in the sourceBundle with parameters.
I have this solution and it works for
script “testscript.scpt”
handler “test_message”
parameter message
NSString* path = [[NSBundle mainBundle] pathForResource:@"testscript" ofType:@"scpt"];
NSURL* url = [NSURL fileURLWithPath:path];
NSAppleScript* theScript = [[NSAppleScript alloc] initWithContentsOfURL:url error:nil];
NSDictionary* theErrorDictionary = nil;
// build Apple event to invoke user-defined handler in script
NSAppleEventDescriptor* event = [NSAppleEventDescriptor appleEventWithEventClass: kASAppleScriptSuite
eventID: kASSubroutineEvent
targetDescriptor: NSAppleEventDescriptor.nullDescriptor
returnID: kAutoGenerateReturnID
transactionID: kAnyTransactionID];
// Add positional parameters
NSAppleEventDescriptor* params = [NSAppleEventDescriptor listDescriptor];
[params insertDescriptor: [NSAppleEventDescriptor descriptorWithString:@"I am a message"] atIndex: 1];
// Add Subroutine
[event setDescriptor: [NSAppleEventDescriptor descriptorWithString: @"test_message"]
forKeyword: keyASSubroutineName];
[event setDescriptor: params
forKeyword: keyDirectObject];
NSAppleEventDescriptor* theResult = [theScript executeAppleEvent:event error:&theErrorDictionary];
NSLog( @"Got result: %@", theResult );
This is the applescript
on test_message(message)
display dialog message
end test_message
No i’d like to pass a dictionary (ASrecord) to applescript, but NSAppleEventdescriptors do not support dictionaries or arrays. Any ideas on how to call an applescript handler with a dictionary parameter?
StefanK
November 5, 2016, 1:29pm
#2
Hi,
they do support dictionaries (record) and arrays (list), you are using one ([NSAppleEventDescriptor listDescriptor])
Consider to write a bridge to AppleScriptObjC, the framework provides to run scripts without the event descriptor dance.
StevenH
November 5, 2016, 2:28pm
#3
The bridge solution sounds good.
Any good starting point for that? Never done before.
StefanK
November 5, 2016, 2:35pm
#4
Please search on MacScripter for loadAppleScriptObjectiveCScripts .
There are a few related topics.
StevenH
November 5, 2016, 11:21pm
#5
Thank you!
I now tried a lot of stuff, but basically this line would not work - throws exception
[[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
Full code from main file
#import <Cocoa/Cocoa.h>
#import <AppleScriptObjC/AppleScriptObjC.h>
int main(int argc, const char * argv[]) {
[[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
return NSApplicationMain(argc, argv);
}
Exception:
[NSBundle loadAppleScriptObjectiveCScripts]: unrecognized selector sent to instance 0x6000000818b0
2016-11-06 00:16:56.850566 MyApp[2717:77340] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSBundle loadAppleScriptObjectiveCScripts]: unrecognized selector sent to instance 0x6000000818b0'
*** First throw call stack:
(
0 CoreFoundation 0x00007fffa92147bb __exceptionPreprocess + 171
1 libobjc.A.dylib 0x00007fffbd981a2a objc_exception_throw + 48
2 CoreFoundation 0x00007fffa9294d84 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x00007fffa9187fc3 ___forwarding___ + 1059
4 CoreFoundation 0x00007fffa9187b18 _CF_forwarding_prep_0 + 120
5 MyApp 0x000000010000efea main + 74
6 libdyld.dylib 0x00007fffbe25d255 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Using Xcode 8, OSX 10.12
StevenH
November 5, 2016, 11:28pm
#6
OK solved that one. Forgot the binary/framework include.
Thank you for pointing it out!
Add-On:
While the above mentioned way works great for text script files (*.applescript), is there also a possibility to send handler calls (with parameters) to precompiled *.scpt files and return a result?
They’re compiled to .scpt files as part of the build process – starting out as .applescript is irrelevant.
When -loadAppleScriptObjectiveCScripts is called, it attempts to load all the .scpt files in a bundle. But you obviously need a script name and parent defined to be able to use them.