Pass an argument to NSUserAppleScriptTask

How do I pass a file url or path, to a script potentially placed in my app's NSApplicationScriptsDirectory?


I admit I haven't used Applescripts much. Normally I'm able to write what I what to do in regular ObjC but it seems scripting is the only way to achieve what I'm after here. So I drop a script in my apps app script directory and do:


NSURL *urlToPassToScript = //...

NSAppleEventDescriptor *event = [NSAppleEventDescriptor descriptorWithString:urlToPassToScript.path];

NSUserAppleScriptTask *task = [[NSUserAppleScriptTask alloc]initWithURL:script error:&error];

[task executeWithAppleEvent:event
                  completionHandler:^(NSAppleEventDescriptor * _Nullable result,
                                      NSError * _Nullable error)
         {
            NSLog(@"Error: %@",error);
         }];


I get:

NSLocalizedFailureReason=/usr/bin/osascript: input data for -E was not an event


So what's the proper way to pass a script an argument?

Accepted Reply

I haven’t looked into this in detail but it would seem that NSUserAppleScriptTask is expecting an event descriptor rather than a data descriptor. You’d construct that with

+appleEventWithEventClass:eventID:targetDescriptor:returnID:transactionID:
. The event class and ID are then mapped to a handler to call within your script. In this case you probably want
kCoreEventClass
and
kAEOpenDocuments
respectively, which translates to the AppleScript
on open
handler. For example:
on open docList
    set docCount to count of docList
    display dialog "count = " & docCount
end open

You supply the list of things to open via the

keyDirectObject
parameter, which you set via
-setParamDescriptor:forKeyword:
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

I haven’t looked into this in detail but it would seem that NSUserAppleScriptTask is expecting an event descriptor rather than a data descriptor. You’d construct that with

+appleEventWithEventClass:eventID:targetDescriptor:returnID:transactionID:
. The event class and ID are then mapped to a handler to call within your script. In this case you probably want
kCoreEventClass
and
kAEOpenDocuments
respectively, which translates to the AppleScript
on open
handler. For example:
on open docList
    set docCount to count of docList
    display dialog "count = " & docCount
end open

You supply the list of things to open via the

keyDirectObject
parameter, which you set via
-setParamDescriptor:forKeyword:
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks a lot for responding with this helpful information. I was able to get it to work after playing with it a bit. My script had an on run function:

on run argv
--stuff
end run


This worked fine when running the script from terminal using osascript, but I wasn't able to get this to work calling it from ObjC. After changing on run to on open I was able to get this to work.


int pid = [NSProcessInfo processInfo].processIdentifier;

NSAppleEventDescriptor *targetDescriptor = [NSAppleEventDescriptor
                                               descriptorWithDescriptorType:typeKernelProcessID
                                                                           bytes:&pid
                                                                          length:sizeof(pid)];

NSAppleEventDescriptor *appleEventDescriptor = [NSAppleEventDescriptor
                                                        appleEventWithEventClass:kCoreEventClass
                                                        eventID:kAEOpenDocuments
                                                        targetDescriptor:targetDescriptor
                                                        returnID:kAutoGenerateReturnID
                                                        transactionID:kAnyTransactionID];

NSAppleEventDescriptor *list = [[NSAppleEventDescriptor alloc]initListDescriptor];



[list insertDescriptor:[NSAppleEventDescriptor descriptorWithString:path] atIndex:1];


[appleEventDescriptor setParamDescriptor:list forKeyword:keyDirectObject];


//pass appleEventDescriptor to the task in when calling executeWithAppleEvent:completionHandler:


How would you call a function with an arbitrary name, or is that not supported? The header file of NSAppleEventDescriptor and documentation seems a little hard to piece together.


Thanks!

How would you call a function with an arbitrary name … ?

I’ve never done that myself but I know it’s related to

kASSubroutineEvent
. Some grovelling around in the docs turned up Technote 2084 Using AppleScript Scripts in Cocoa Applications.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I see Apple forum software is still utterly broken and incompetent.

I have a lovely long detailed and very helpful reply already written for Mr Savage. If he would like to repost his original question on the Cocoa-dev mailing list I will be delighted to provide it there.