Overview of Cocoa Support for Scriptable Applications
This chapter provides an overview of Cocoa scripting and how your application takes advantage of it, and provides links to more detailed information in other chapters and documents.
A scriptable application is one that scripters can control with AppleScript scripts. To create a scriptable application, you specify a dictionary of terms that scripters can use with your application, implement classes and methods to support scriptable features, and provide a road map of scriptability information that AppleScript and Cocoa use to allow scripts to control the application.
Cocoa scripting refers to the support provided by the Cocoa application framework for creating scriptable applications. It includes classes, categories, and scriptability information that specifies the supported AppleScript terminology and the class information needed to work with it.
Cocoa scripting makes use of standard mechanisms and design patterns used throughout Cocoa, including key-value coding (KVC) and Model-View-Controller (MVC). When an AppleScript command targets your application, the goal of the scripting support is to send the command directly to the application's model objects to perform the work. To do that, it relies on the KVC mechanism to get and set values in your application's scriptable model objects, based on a set of keys you define for them.
Through the use of these mechanisms, you can make your application scriptable with a minimum of additional code.
AppleScript and Scriptable Applications
AppleScript is a scripting language that makes possible direct control of scriptable applications and scriptable parts of the Mac OS (such as the Finder). The AppleScript language doesn’t supply an exhaustive or a task-specific terminology. Instead, it defines common commands, such as
delete, which can be applied to a wide variety of objects or their properties in a scriptable application. Scriptable applications define additional terms as needed for their unique operations.
A scriptable application is one that makes its operations and data available in response to AppleScript messages, called Apple events. An Apple event is a kind of interprocess message that can specify complex operations and data. Apple events make it possible to encapsulate a high-level task in a single package that can be passed across process boundaries, performed, and responded to with a reply event.
A scriptable application specifies the set of scripting terms it understands and provides information that AppleScript uses to compile scripts that use those terms. When a user executes a script that targets the application, Apple events are sent to the application. Apple events can also be sent by other applications and by the Mac OS.
Applications handle Apple events by registering with the Apple Event Manager for the events they expect to receive and by supplying handler routines to process the events. Cocoa scripting simplifies this process by automatically registering and responding to Apple events your application can handle, based on the scriptability information you supply. That means you don't need to write low-level code to interact with Apple events and the Apple Event Manager.
AppleScript and Apple events are built on the Open Scripting Architecture (OSA), which is described in “Open Scripting Architecture” in AppleScript Overview.
The AppleScript Object Model
Every scriptable application defines an AppleScript object model to specify the classes of objects a scripter can work with in scripts, the accessible properties of those objects, and the inheritance and containment relationships for those classes. Inheritance allows a class to access the properties of its ancestors. Containment specifies where an object resides within the hierarchy of objects in the running application.
The objects in the object model often correspond closely to object classes in the application that implement scripting support, but there is no requirement that they do so. For example, a text application might provide script access to words in a document, but it would not be efficient for the application to maintain a corresponding object for each word.
Application classes have attributes, to-one relationships, and to-many relationships. AppleScript classes in the object model have properties and elements—properties are synonymous with attributes and to-one relationships, while elements are synonymous with to-many relationships. For more information on these and related terms, see the “Glossary.”
Figure 1-1 shows the object-model containment hierarchy for a specific document (shown in Figure 1-2) in the Sketch application. On the left are the objects a scripter uses to work with the application. On the right are the objects that Sketch uses to represent its object model.
In this object model, documents are elements of the application object and graphics are elements of document objects, while the name of a document is a property of the document. For a script to access an object in the hierarchy, it must locate the object within its containment hierarchy. (In the application, the
orderedDocuments array is a to-many relationship of the
Consider, for example, the following sample script:
tell app "Sketch" to set the x position of rectangle 1 of document "SketchDocOne" to 25
This script specifies a rectangle, in a document, in the application. If applied to the following Sketch document, it would set the horizontal (x) position for whichever of the two rectangle shapes is first in the document's ordered list of graphics.
A script can ask for
rectangle 1 of document "SketchDocOne" without having to specify either
documents (though they are part of the hierarchy shown above) because an AppleScript class definition implicitly specifies the relationships of its contained elements.
Sketch's object model uses inheritance for its graphics objects. All such objects (
text area) inherit from a common ancestor (
graphic). Thus the term
graphic 1 of document "SketchDocOne" might specify the same object as
rectangle 1 of document "SketchDocOne", depending on the ordering of the objects in the graphics array.
A scriptable application supplies scriptability information that formally lays out the AppleScript object model for the application and maps it to application objects. This scriptability information does two things:
It specifies the terminology available for use in scripts that target the application and supplies comments on the purpose and usage for that terminology.
It provides information, used by AppleScript and by Cocoa, about how support for that terminology is implemented in the application.
This information includes the KVC keys that Cocoa scripting uses to gain access to attribute and relationship information in the application's classes. Without these keys, scripts would not be able to manipulate properties of scriptable objects in the application's object model.
To uniquely identify terms in its scriptability information, an application uses constants called four-character codes (or Apple event codes). A four-character code is just four bytes of data that can be expressed as a string of four characters in the Mac OS Roman encoding. These codes are described in “Code Constants Used in Scriptability Information.”
Within an application's scriptability information, terminology associated with related functionality (for example, operations involving text, graphics, or databases) are generally collected into suites. Cocoa provides the predefined suites described in “Built-in Support for Standard and Text Suites.”
AppleScript uses the application’s scriptability information, including four-character codes, to compile scripts and send Apple events to the application. Cocoa uses the information to interpret received Apple events and create script command objects to perform the specified operations.
Scriptability Information Formats
You define your application’s scriptability information using one of two formats. The first is the scripting definition or sdef format. This is an XML-based format that describes a set of scriptability terms and the commands, classes, constants, and other information that describe the application's scriptability. The sdef format was introduced in OS X version 10.2 and is used natively by Cocoa starting in OS X version 10.4. In the sdef format, an application's scriptability information is contained in a single scripting definition (or sdef) file, with the extension
.sdef. The word sdef can be used to describe either the format or a file in that format.
A second, older format uses property list files and is referred to as the script suite format. It supplies Cocoa and AppleScript with roughly the same information, in the form of a script suite file and a corresponding script terminology file:
A script suite file describes scriptable objects in terms of their attributes, relationships, and supported commands, and has the extension
A script terminology file provides AppleScript terminology—the English-like words and phrases a scripter can use in a script—for the class and command descriptions in the corresponding script suite file. Script terminology files have the extension
Defining scriptability information with either of these formats is a bit like defining your application interface with nib files, though you work with text rather than a graphic editor. In both cases you provide information up front that Cocoa uses at specific times to create objects and provide support for the task at hand. The information from an sdef (or the older property list form) is loaded just once per application launch, as described in “Loading Scriptability Information.” The loaded information is then used as needed to create script command objects to perform scriptable operations.
A scripting definition file follows the XML format defined in the sdef man page and described in more detail in “Preparing a Scripting Definition File.” Figure 1-3 shows the main XML elements in an sdef file.
As an example of specific sdef elements, Listing 1-1 shows the
rectangle definitions from Sketch's sdef file. The
graphic class defines several properties (such as
x position and
y position) that are inherited by other shape classes. The
rectangle class adds an
orientation property and specifies that the object responds to the
rotate command, which is specific to rectangles.
Listing 1-1 Graphic and rectangle elements from Sketch's sdef file
... (from the Sketch suite)
<class name="graphic" code="grph"
description="A graphic. This abstract class represents the
individual shapes in a Sketch document.
There are subclasses for each specific type of graphic.">
<property name="x position" code="xpos" type="real"
description="The x coordinate of the graphic's bounding rectangle."/>
<property name="y position" code="ypos" type="real"
description="The y coordinate of the graphic's bounding rectangle."/>
<property name="width" code="widt" type="real"
description="The width of the graphic's bounding rectangle."/>
... (some properties omitted)
<class name="rectangle" code="d2rc" inherits="graphic"
description="A rectangle graphic.">
<property name="orientation" code="orin" type="orientation"/>
Viewing Scripting Terminology
Users typically examine scripting terminology in a dictionary viewer to discover which features are scriptable and how to script an application. You can view the scripting terminology for a scriptable application with Script Editor or Xcode. Figure 1-4 shows the sdef file from the Sketch application in a dictionary viewer, with the graphic and rectangle classes visible.
Double-clicking an sdef file in the Finder opens it in a dictionary viewer like the one shown above. Double-clicking an sdef file in an Xcode project similarly opens it in a dictionary viewer window. To view or edit the XML for the file, open the sdef file with any plain text editor; in Xcode, select the sdef file and choose File > Open As > Plain Text File.
For related information, see “Editing Scriptability Information.”
Built-in Support for Standard and Text Suites
A scriptable application typically supports certain standard AppleScript terms, such as the
make commands and the
application class. Cocoa provides built-in support for these terms in the Standard suite. It also provides command classes, including
NSCreateCommand, to implement standard commands. In addition, classes such as
NSDocument implement certain aspects of standard scripting support.
Cocoa scripting also provides support for the
set commands, including implementation of the command classes
NSSetCommand. These commands are not part of the Standard suite, but are considered built-in AppleScript commands. Allowing scripters to get and set the values of properties and elements of scriptable objects is a key part of making an application scriptable.
The Standard suite defines the following AppleScript commands: (for all classes)
move; (for documents and windows)
close. Note that there is no default implementation for the
To support text-related classes such as
paragraph, Cocoa implements the Text suite.
Cocoa’s built-in support for the Standard and Text suites is described in more detail in “Use the Document Architecture” and “Access the Text Suite.” To include it in your application, you follow the steps described in “Turn On Scripting Support in Your Application”.
Built-in Support for Basic AppleScript Types
Cocoa scripting provides built-in support for basic AppleScript types and automatically associates them with appropriate Cocoa data types, as shown in Table 1-1. You can use these types without declaring them in your sdef file.
This type is used as the type of the
Loading Scriptability Information
When an application first needs to work with scriptability information, Cocoa scripting uses a global instance of
NSScriptSuiteRegistry to load information from the application's sdef file:
For each class described in the sdef file, it instantiates a class description object (
NSScriptClassDescription) that stores information about objects of that type.
This information includes the KVC keys that Cocoa scripting uses to access values of the application's scriptable objects.
For each script command described in the sdef file, it registers a handler routine for Apple events that specify that command.
It also instantiates a command description object (
NSScriptCommandDescription) that stores information such as the name of the scripting command class to instantiate to perform the command, as well as the command's arguments, and return type (if any).
Figure 1-5 shows the loaded class and command descriptions for an application. Cocoa uses the information to create instances of command classes and descriptions of application objects that it needs to handle Apple events received by the application.
Application scriptability information automatically includes information to support the basic AppleScript types listed in Table 1-1 and to make the
set commands available to all applications.
Reliance on Key-Value Coding
Key-value coding (KVC) is a mechanism for accessing object properties indirectly by key. A key is just a string that identifies a property, such as
"xPosition" for the horizontal coordinate of a graphic object (shown in Listing 1-1). The KVC API provides a generic way to query an object for the values of its keys and to set new values for those keys.
Cocoa scripting relies on KVC for the following purposes:
Command objects use KVC to find the specified scriptable objects on which to operate.
For many commands, Cocoa uses KVC to access properties of the specified objects to get or set their values.
As you design the object classes for your application, you also define keys for their scriptable properties. Your application provides these keys in
class definitions in its sdef file. Then, when you implement accessor methods (or declare instance variables) that correspond to these keys, you make it possible for Cocoa scripting and KVC to get and set the corresponding values.
Default naming for keys is described in “Provide Keys for Key-Value Coding.” For information on naming accessor methods, see “Maintain KVC Compliance.”
Interaction With Cocoa Bindings and Core Data
Cocoa scripting, Cocoa bindings, and Core Data are three development technologies available in OS X that rely on key-value coding:
Cocoa scripting, described throughout this document, provides support for creating scriptable applications.
The Core Data framework provides generalized and automated solutions to common tasks associated with object life-cycle and object graph management, including persistence. It is described in detail in Core Data Programming Guide.
Cocoa bindings provides a means of keeping model and view values synchronized, without having to write a lot of "glue code," such that a change in one is reflected in the other. It is described in detail in Cocoa Bindings Programming Topics.
As noted, all three of these technologies rely on KVC, so you will gain by making your application KVC-compliant. Cocoa bindings and Core Data also make use of key-value observing, but Cocoa scripting does not.
While these technologies are not closely tied together, here are some rules of thumb that may aid in combining their use:
Core Data and Cocoa bindings: These technologies neither aid nor interfere with each other, so you can mix them as needed for your application.
Core Data and Cocoa scripting: Because Cocoa scripting deals in ordered to-many relationships, and Core Data deals in unordered to-many relationships, you must do extra work to expose the to-many relationships of your managed objects as scriptable element classes. For each managed-object to-many relationship that you want to make scriptable, you can add an unmanaged, derived, to-many relationship solely for access by Cocoa scripting. For information about how to implement these derived to-many relationships, see "Indexed Accessor Patterns for To-Many Properties" in “Key-Value Coding Accessor Methods” in Key-Value Coding Programming Guide and “Getting and Setting Properties and Elements” in this document.
Cocoa scripting and Cocoa bindings: Again, these technologies neither aid nor interfere with each other. If you're using bindings but not Core Data, you probably have ordered relationships, which will work with Cocoa scripting.
For related information, see “Interaction With Key-Value Observing.”
Scriptability and Undo
Scriptable applications should generally support undo of scripted operations as they would any user-initiated operation. That is, after a script causes the application to perform one or more operations, a user should be able to sequentially undo the operations in the normal manner.
Cocoa scripting provides no special support for undo, but neither does it interfere with normal undo operations. Applications that take advantage of the Model-View-Controller paradigm and Cocoa's key-value coding mechanism, as scriptable applications are designed to do, are well-positioned to support both scriptability and undo.
For more information on supporting undo, see Undo Architecture.
Snapshot of Cocoa Scripting
The work done by your scriptable application is divided between the application and Cocoa scripting. Your application implements classes and methods that perform its scriptable operations; it also provides information that describes its scriptability. Cocoa receives Apple events and uses your scriptability information to interpret them and perform the specified operations, calling on your code to do the actual work.
Here is a summary of how this process works:
The application defines scriptability information (in an sdef file, or in the older style script suite and script terminology files) that includes both the terms a scripter can use and the application information for supporting those terms. This information typically includes the Standard suite (implemented by Cocoa scripting), which supports standard AppleScript commands and classes.
The application defines classes for the scriptable objects it supports and provides keys for their scriptable properties and elements. It also defines additional script command classes if it has scriptable operations that can't be performed by one of the standard command classes provided by Cocoa.
Scriptability is generally provided through the application's model objects (in terms of the Model-View-Controller paradigm).
The application is key-value coding (KVC) compliant in naming the instance variables or accessor methods for the scriptable properties and elements of its scriptable classes.
For each scriptable class, the application implements an object specifier method, which locates a scriptable object of that type within the application’s containment hierarchy.
Info.plistfile has entries that activate Cocoa scripting and specify an sdef file, as shown in “Turn On Scripting Support in Your Application.”
When it is first needed, Cocoa loads the application's scriptability information and automatically registers event handlers for the supported commands.
When the application receives an Apple event for a registered command, Cocoa instantiates a script command object containing all the information needed to identify the application objects on which the command should operate. All command objects use KVC to locate the specified scriptable objects to operate on.
Cocoa then executes the command, which sends messages to the appropriate application objects to perform the work. For many commands, Cocoa uses KVC to get or set values of the specified objects.
When a command needs to return a value, Cocoa scripting packages the information in a reply Apple event and returns it.
If an error occurs while executing the command, Cocoa returns the error information (including any information added by the application) in the reply Apple event. For details, see “Error Handling.”
If a command requires asynchronous processing (such as the gathering of information through a sheet), the application can suspend it, so that the application doesn't receive additional Apple events during processing. For details, see “Suspending and Resuming Apple Events and Script Commands.”
A Real World Scripting Example
To track a scripting command from the execution of an AppleScript script to the operation it performs in the targeted application, consider again the following one-line script, which attempts to set a value in a document of the Sketch application:
tell app "Sketch" to set the x position of rectangle 1 of document "SketchDocOne" to 25
When this script is compiled against Sketch's scriptability information and executed, it results in an Apple event being sent to the Sketch application. The Apple event encapsulates the
set command and specifies an operation on an object in the
"SketchDocOne" document shown in Figure 1-2. Figure 1-6 illustrates the actions that result when the application receives the
set Apple event.
Here is a description of the steps shown in this figure:
The application receives the Apple event specifying a
The Apple event translator, a part of Cocoa scripting, uses scriptability information supplied by the application to evaluate the Apple event. This information is pictured in more detail in Figure 1-5.
The translator creates an instance of an
NSSetCommandscript command and initializes it with the information need to perform the command:
The direct parameter of the
setcommand specifies the object or objects to set the value for (in this case, the first rectangle), and becomes the receivers specifier in the
toparameter provides the value to set (in this case,
25) and becomes the "Value" argument in the
These values are stored in the command object as an argument dictionary. For information on how your application works with that information, see “Script Command Components.”
setcommand is executed, it uses KVC to locate the specified object or objects. It also relies on KVC to set the specified value. For additional detail, see “Getting and Setting Properties and Elements.”
Some commands return a value, but the
setcommand does not.
As this example and the information in “Snapshot of Cocoa Scripting” show, an application can support the
set command with a relatively modest effort: it modifies its
Info.plist file to indicate it is scriptable and to specify its sdef file; it provides command and class information in the sdef file; and it maintains KVC compliance for scriptable properties in its scriptable classes.
If the application also implements an
objectSpecifier method for each of its scriptable classes, it can support the
get command as well. Cocoa scripting uses KVC to get the specified value from the application and package it up in a return Apple event.
As a result, an application can rather quickly supply a great deal of scriptability just by supporting
set access to properties of a few key objects.
Current Limitations of Cocoa Scripting Support
There are some scripting-related features for which Cocoa scripting currently provides little or no support.
However, Cocoa applications are free to use C functions from the Apple Event Manager. So, for example, your application could use an instance of
NSAppleEventDescriptorto assemble the information for an Apple event, invoke the
aeDescmethod to get an Apple event data structure, and use that structure with the C functions described in Apple Events Programming Guide to send the Apple event.
Recording. A recordable application sends itself Apple events, which can be assembled by the Script Editor application into a script that “records” the user’s actions (when recording is turned on in Script Editor).
Cocoa scripting does not currently enforce the
read/write status specified in an sdef, so marking a property as read-only does not ensure that it cannot be written. (Read/write access is described in “Property Elements.”)