Online Book Reader

Home Category

AppleScript_ The Definitive Guide - Matt Neuburg [257]

By Root 1606 0
our class is called MyScriptCommand, so now we create that class. In Xcode, choose File → New File, making the new file an Objective-C class and calling it MyScriptCommand. In the header file, make MyScriptCommand a subclass of NSScriptCommand. In the implementation file, enter this code:

@implementation MyScriptCommand

- (NSAppleEventDescriptor*) doAS: (NSString*) s {

NSAppleScript* as = [[NSAppleScript alloc] initWithSource:s];

NSAppleEventDescriptor* d = [as executeAndReturnError:nil];

[as release];

return d;

}

- (id) performDefaultImplementation {

NSString* s = @"tell current application "

@" to perform action of button 1 of window \"search\"";

[self doAS:s];

return nil;

}

@end

In our override of the performDefaultImplementation method, we get to implement our own functionality for this command. Once more we have not tried to solve the problem of communicating from Objective-C to AppleScript; instead, we have again used the interface as a medium of indirect communication. We can't call the clicked handler directly, so instead we effectively press the Search button, using an AppleScript Studio command that permits us to do so, and this triggers the clicked handler already tied to that button.

Even though we can't send messages from Objective-C to AppleScript, perhaps we can improve the way we send messages to the interface. At present we are forming a script as text on the fly and then compiling and executing it. This way is very slow, uses a lot of unnecessary overhead, and may be justly charged with a certain fragility. To give just one example, if the user says set search text to with a value that contains a quote character, our setSearchText: method will break, because of the blithe way it constructs a literal string. That's clearly a bug.

I will conclude, therefore, by demonstrating a more elegant architecture that uses a compiled script as an intermediary (a "trampoline"). We will call into this compiled script with an Apple event, and the compiled script will send an Apple event to our interface. Apple events are fast, and running a compiled script is fast; it's compiling text on the fly that's slow. And this approach will be immune to the bug with strings containing a quote, because we will never "unpack" an AppleScript string—we will pass it along directly to the compiled script, and we know that this will work because the string must have been a valid AppleScript string to start with (or we could never have received it in the first place).

Start with a script encapsulating the AppleScript code we're already using to get and set the contents of a form cell in the Search window:

on setCell(n, s)

tell current application

using terms from application "Automator"

set content of cell n of matrix 1 of window "search" to s

end using terms from

end tell

end setCell

on getCell(n)

tell current application

using terms from application "Automator"

get content of cell n of matrix 1 of window "search"

end using terms from

end tell

end getCell

The terms blocks, targeting Automator, are a trick: in order for the central lines to compile, we must resolve them with respect to AppleScript Studio's terminology; Automator's dictionary contains this terminology.

Now compile the script (at which point Automator's task is done, because it is never actually targeted), and save it as trampoline.scpt. Add it to the SearchTidBITS project so that it will be copied into the built application bundle.

Because we might be using this script any time the user targets the SearchTidBITS application, we'll save time by loading it once and for all into an NSAppleScript* instance variable (called trampoline) as our application starts up:

- (void) awakeFromNib {

NSString* path = [[NSBundle mainBundle] pathForResource:@"trampoline"

ofType:@"scpt"];

NSURL* url = [NSURL fileURLWithPath:path];

trampoline = [[NSAppleScript alloc] initWithContentsOfURL:url error:nil];

}

When the user wants to get or set any of the properties search text or search title or search author, we will call the corresponding handler

Return Main Page Previous Page Next Page

®Online Book Reader