AppleScript's Object Hierarchy
If you are familiar with AppleScript, you might already see the link between the AppleScript syntax and this object heirarchy.
tell application "MyApp" get the first word of the first paragraph of document 1 end tell
This is a typical AppleScript snippet. The heirarchy here goes from the
generic application object
MyApp to the document object
to paragraph object
first paragraph to word object
first word. These
map, in AppleScript speak, to elements and their properties. Let's look
at a little more AppleScript syntax, and then we'll put it all together.
tell application "Graphics App" set the color of window 1 to "blue" end tell
Breakdown of "ScriptableApp"
line by line "activate" is a command to application "ScriptableApp"
the set command to AppleScript with the arguments a script variable "appName" and the results of the command "name" sent to the application.
the set command to AppleScript with the arguments a script variable "appVersion" and the results of the command "version" sent to the application.
the set command to AppleScript with the arguments a script variable "numWins" and the count property of the collection of window elements in the application.
the set command to AppleScript with the arguments a script variable "numDocs" and the count property of the collection of document elements in the application.
the set command to AppleScript with the arguments a script variable "w" and the index property of the last element of the collection of windows returned by the get command with the identifier of every sent to the application.
close is a command sent to the application.
The topmost scripting object is the application
Graphics App. This
script is looking for an element identified by the word
the properties of that element being
color and an index of
could have also been
mid, or any collection identifier), and
we send the
set command to the application with the arguments of the
property of the element identifier and the new value of that property.
tell application "ScriptableApp" activate set appName to name set appVersion to version set numWins to count of windows set numDocs to count of documents set w to the last Abstract object of (get every window) close w end tell
Now, this one is a little more complicated, but try to find the elements, properties, and commands, and which object is being asked to do what. You should try to imagine what the object hierarchy for this application might look like.
Adding AppleScript support to a Cocoa application is a matter of providing a map between the elements and their properties of a scriptable application, and the Cocoa objects or other objects that make up that application, including the application object iteslf. Now while this may seem daunting, we are fortunate that Apple has already done this for us with the Core Suite for the most common Cocoa objects used in applications that are normally scriptable.
Core Suite and "For Free"
In the first article, we set the key
YES in the
info.plist and gained a lot of scriptability right away.
This scriptability comes from activating the Core Suite available to all
Cocoa applications. The Core Suite provides a map for us.
our Cocoa application is a bunch of objects, primarily an instance of
main.m) and an instance of
MainMenu.nib). The window may be a little confusing, if you haven't
looked at other tutorials on Cocoa and using Project Builder and
You can use Interface Builder to create instances of
UI objects, which are stored in .nib files and are loaded automatically
when the application launches. This is all done graphically, so there is
no corresponding source code viewable in Project Builder. There are some
other objects floating around, like
NSWindowController, and others, but they are not typically scriptable, so
we will not focus on them. The Core Suite identifies certain Cocoa
classes that will be scriptable. We can see these classes in a file
NSCoreSuite.scriptSuite, located at
You can look at this file in a text editor, or in a program called
Property List Editor in the
/Developer/Applications directory. This XML
file has a lot of information in it, so I would recommend using the
Property List Editor, just to make it easier to see what is going on.
NSCoreSuite.scriptSuite has several top-level keys: AppleEventCode,
Classes, Commands, Enumerations, Name, and ValueTypes. For now, let us
look at the Classes and Commands sections. The Classes mentioned are
For Commands, we see Close, Copy, Count, Create, Delete, Exists, Get, Move, Open, Print, Quite, Save, snd Set. If you look at ScriptableApp's script dictionary, you'll see just these items. Every item has its own AppleEventCode associated with it, and if you look through the Classes, you'll see keys for the Superclass of the class and the SupportedCommands. Also, keep in mind that these classes can inherit attributes and commands from their Superclass, as each of the later classes do from AbstractObject.
NSCoreSuite.scriptSuite in Property List Editor
The Commands section matches each command up with a Cocoa object that is
a subclass of
NSScriptCommand. This is the CommandClass key found in
For example, Copy is matched with an
object. Each time a command is used in a script, an object of the
corresponding type is created to ensure that the command is carried out. If
you are more experienced with object-oriented programming, this may seem
a little odd, as commands (methods) are usually defined along with
their objects, so this breaks the OOP paradigm. However, AppleScript is
designed to have a small number of commands that work on a large number
of elements, so this arrangment works best for that idea.
also define an AppleEventClassCode, in additional to the AppleEventCode,
and their Arguments and return Type. A command may not have either
arguments or return types, and if so, those keys are simply left blank.
Return types are usually of the type
NSNumber, but they can
be other classes as well. There are many more items in this file, and we
will talk more about them in later articles, especially when we start to
create our own script suites, but now let us turn our focus more towards
the AppleScript side.