Sunday, November 26, 2006

NSAppleScript is slow...

Within the documentation for NSAppleScript is the following:
You should access NSAppleScript only from the main thread.

This would normally be OK, except for the fact that NSAppleScript can be slow. It only provides an executeAndReturnError: method, which means that if you invoke this method, your application will stall until your AppleScript has completely finished. So imagine running a script like this (tell application "iTunes" to play). If iTunes isn't already open, your application will have to wait for iTunes to launch. Is there anyway around this?

Sure there is. Just run the applescript in a background thread using NSTask. Like this:

- (void)backgroundThread:(id)obj
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSString *command = @"tell application \"iTunes\" to play";
NSMutableArray *args = [NSMutableArray arrayWithObjects:@"-e", command, nil];

NSTask *task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath:@"/usr/bin/osascript"];
[task setArguments:args];

[task launch];
[task waitUntilExit];

[pool release];

PS- I've had really odd problems with the waitUntilExit method in the past. It would randomly cause crashes. If you have the same problem, I recommend using code like this in place of the waitUntilExit method:

do {
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
} while([task isRunning]);

I realize it's not exactly the best solution in the world, but it gets the job done, and it's never crashed on me.

PPS - For information on creating the background thread, see the previous post entitled "Easy threading in Cocoa."


No comments: