davidb
davidb

Reputation: 357

How can I queue NSUserAppleScriptTask executions?

I am migrating some code that executes AppleScripts from NSAppleScript to NSUserAppleScriptTask so that I can sandbox my app. The problem I am having can be best demonstrated as follows:

The AppleScript "test.scpt" is simply

on run
  display dialog "Hello World" buttons {"OK"} default button "OK"
end run

If I execute this 10 times in a row with NSAppleScript as below, the script is executed 10 times, with each execution waiting for the previous execution to complete.

NSURL *script = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"scpt"]];

for (int i=0; i<10; i++) {

    NSDictionary *error = nil;
    NSAppleScript *task = [[NSAppleScript alloc] initWithContentsOfURL:script error:nil];
    [task executeAndReturnError:&error];
    if (error!=nil) {
        NSLog(@"AppleScript error: %@", error);
    }
    [task release];
}

However using NSUserAppleScriptTask it appears the tasks are executed concurrently. The concurrent executions is a "problem" as it seems that if a previous script has a dialog open, the next script to be executed errors. This can be demonstrated as below:

NSURL *script = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"scpt"]];


for (int i=0; i<10; i++) {

    NSError *error;
    NSUserAppleScriptTask *task = [[NSUserAppleScriptTask alloc] initWithURL:script error:&error];
    [task executeWithCompletionHandler:^(NSError *error) {
        if (error){
            NSLog(@"Script execution failed with error: %@", [error localizedDescription]);
        }
    }];

   [task release];

}

This generates the following error for 9 out of the 10 executions:

execution error: "Hello World" doesn’t understand the «event sysodlog» message. (-1708)

I thought the correct solution would be to queue each operation using gcd or NSOperationQueue, but I've not managed to construct a queue that waits for the completion block of the NSUserAppleScriptTask to be executed before it starts the next task.

Can anyone suggest a solution that would give me the same behaviour as the NSAppleScript method gives me?

Upvotes: 1

Views: 1295

Answers (3)

fabe
fabe

Reputation: 496

how did you get past the sandboxing? Whatever I try I keep getting something like:

Script execution error: The file “create.scpt” couldn’t be opened because you don’t have permission to view it.

When sandboxing is turned of or the script is executed manually everything works

entitlements:

com.apple.security.temporary-exception.apple-events
com.apple.systemevents
com.apple.applescript

TY.

Edit: It seems that if i put the script into ~/Library/Application Scripts/com.myapp/ and execute that script everything works fine

Upvotes: 0

Martin R
Martin R

Reputation: 539975

(Motivated by omz's comment above I'm writing this as an answer.)

You could use the completion handler of the task to start execution of the next task.

Upvotes: 1

omz
omz

Reputation: 53561

You could run the scripts from a dispatch queue (or operation queue) and use an NSConditionLock to wait for each script to complete.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:0];

    NSURL *script = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"scpt"]];
    for (int i=0; i<10; i++) {
        NSError *error;
        NSUserAppleScriptTask *task = [[NSUserAppleScriptTask alloc] initWithURL:script error:&error];
        [task executeWithCompletionHandler:^(NSError *error) {
            if (error){
                NSLog(@"Script execution failed with error: %@", [error localizedDescription]);
            }
            [lock lock];
            [lock unlockWithCondition:1];
        }];
        [task release];

        //This will wait until the completion handler of the script task has run:
        [lock lockWhenCondition:1];
        [lock unlockWithCondition:0];
    }
    [lock release];
});

Upvotes: 2

Related Questions