Implementing a Scriptable Application
This chapter lists the key steps for implementing a scriptable Cocoa application, with links to more detailed information where necessary.
Once you have completed one of the design phases described in “Designing for Scriptability,” you use steps like the following to implement a scriptable Cocoa application:
For a new application, implementing scriptability should be an integral part of creating the application. That is, you’ll be creating scriptable classes, adding scripting accessor methods, and so on, as you implement other parts of the application.
When you’re adding scriptability to an existing application, there is more opportunity for a staged or incremental approach. That is, you may want to test your approach by retrofitting one or a small number of classes, before extending it to the entire application.
In either case, your work should include milestones to test each phase of scriptability, as spelled out in your test plan.
Cocoa follows the Model-View-Controller (MVC) design pattern, where model objects encapsulate and manipulate the data used by the application. You should generally support scriptability in your model objects, which tend to be more persistent. Although there may be some cases where you want to allow scripting of your view objects, keep in mind that scripts that operate on the user interface tend to be fragile, and they can also be less efficient.
For more information, see “Concentrate Scriptable Behavior in Model Objects.”
Provide an sdef file with the scriptability information for your application.
For more information, see “Supply a Scripting Definition File.”
Maintain key-value coding (KVC) naming compliance for instance variables or accessor methods for scriptable properties and elements, based on the keys in your sdef file. Cocoa scripting support relies on this naming compliance.
For details, see “Maintain KVC Compliance.”
Include the sdef file in the Xcode project for your application, as described in “Add the Scripting Definition File to Your Xcode Project.”
Modify your application’s
Info.plistfile to turn on Cocoa scripting support and identify your sdef file, as described in “Turn On Scripting Support in Your Application.”
Cocoa implements the
NSScriptCommandclass and a number of specific subclasses, such as
NSSetCommand. However, for some commands implemented by Cocoa, your application may need to provide a different implementation.
For information on how to do this, see “Steps for Implementing a New or Modified Script Command.”
objectSpecifiermethods for scriptable classes in your object model. These methods describe the object and point to its parent in the object containment hierarchy (with the application object generally serving as the outermost container). They are invoked by an instance of
NSGetCommandwhen it works with your application to obtain the requested information.
If you’ve created helper classes to add scriptability to an existing application, these classes also need to implement object specifier methods.
For more information, see “Implement Object Specifier Methods for Scriptable Classes.”
Implement any new script command subclasses your application requires.
Many applications provide unique capabilities, such as rotating an image or converting between two audio formats. To make these features scriptable, you may need to define new script command classes that are subclasses of
NSScriptCommandor one of the other command classes provided by Cocoa.
For more information, see “Subclasses for Standard AppleScript Commands” and“Script Commands Overview.”
To take advantage of Cocoa scripting support that works with document and window classes, your application should use the Cocoa document architecture.
For more information, see “Use the Document Architecture.”
To take advantage of Cocoa scripting support that works with text, your application can take advantage of Cocoa's built-in support.
For more information, see “Access the Text Suite.”
Throughout the implementation process, test your application according to the test plan you developed.
For tips and suggestions, see “Testing, Debugging, and Performance.”
Supply a Scripting Definition File
Every scriptable application must provide a definition of its scriptability information—the terminology available for use in scripts that target the application, as well as the implementation information used to support that terminology. This information includes a set of keys for the scriptable properties accessible in the application through key-value coding (described in “Provide Keys for Key-Value Coding”).
If you developed an sdef file during the design phase, you've already completed this step. If not, see “Preparing a Scripting Definition File” for a description of the steps you take to create an sdef file and add scriptability information to it.
For information on working with the older scriptability format, see “Script Suite and Script Terminology Files.”
Concentrate Scriptable Behavior in Model Objects
The Model-View-Controller (MVC) paradigm is one of the central design patterns for Cocoa applications. MVC assigns objects in an application to one of three roles and recommends that you try to maintain a separation among objects of different roles.
Model objects encapsulate the data and basic behaviors of the application; ideally, they have no explicit connection to the user interface.
View objects present data to the user; they know how to display and possibly edit data, but typically do not encapsulate any data that is not specific to displaying or editing.
Controller objects act as an intermediary, coordinating the exchange of data between the model and view objects.
Generally, the objects that you make scriptable should be model objects. The most efficient way for a script to perform a task generally involves modifying the model and is often not the same as the best way for a user to do the same task through the user interface (or view). This is consistent with how AppleScript works, and Cocoa accordingly gears its scripting support to the model layer.
A script should not require the user’s involvement, unless it is intended more as a macro than as a form of batch processing. In a macro-like script, the user must prepare things for the script (such as opening a window and creating or selecting certain objects), and then invoke it. If you anticipate that your application will be scripted for this purpose, you may want to provide scriptable behavior to the appropriate nonmodel objects, such as windows and selections. If so, be sure to confine your scripting support in nonmodel objects to those specific purposes.
Provide Keys for Key-Value Coding
Recall that key-value coding (KVC) is a mechanism for accessing object properties indirectly by key, where a key is just a string that represents a property name (such as
"xPosition" for the horizontal coordinate of a graphic object). Cocoa scripting relies on KVC, both for finding the specified objects for a command to operate on and for getting and setting values in the specified objects.
Your application provides keys for its scriptable properties and elements in
class definitions in its sdef file. The property and element names themselves serve as keys, unless you specify a different key explicitly. Cocoa scripting adjusts the key names as necessary according to the following rules, which are consistent with standard Cocoa naming conventions for accessors:
For single-word property names, the name becomes the key. For example, an sdef property named
"width"would result in a key of
For multiple-word property names, Cocoa capitalizes each word of the name except the first word, then removes any spaces. For example, an sdef property named
"desktop position"would result in a key of
For element names, Cocoa specifies a key by making a plural from the name. For example,
"word"results in a key of
You can override the default naming conventions to specify arbitrary key values where necessary. For example, suppose you want a scripter to be able to use
color in a script, but your application refers to the underlying property as
foregroundColor (as in the
NSTextStorage class). You can specify
"foregroundColor" as the key for the
"color" property by adding a
cocoa key entry to the sdef
<property name="color" code="colr" ...
To support getting and setting scriptable properties and elements in your application, you define accessor methods that match the keys in your sdef, as described in “Maintain KVC Compliance.” For additional information on default naming and working with keys, see “Cocoa Elements.”
Add the Scripting Definition File to Your Xcode Project
Once you have created an sdef file, you'll need to add it to the Xcode project for your application. Place the file in the project folder (or other appropriate location) and use Project > Add to Project, which also lets you add the sdef file to application targets. Adding the sdef file to the project automatically adds it to the Copy Bundle Resources build phase, so it will be included in the application.
Turn On Scripting Support in Your Application
To turn on Cocoa’s built-in scripting support, you add the following key to your application's
To provide your application's scriptability information through an sdef file, you add a second key to the property list to specify the sdef file. Here's the entry for the Sketch application:
Implement Object Specifier Methods for Scriptable Classes
An object specifier locates a scriptable object or objects within the containment hierarchy in which they reside.
When a script statement targets an application, the application may need to return a reply. For example, the result of a
get command is an object or a list of objects. When Cocoa returns these objects in the reply Apple event, it does not return pointers to Objective-C objects, it returns object specifiers.
To obtain the object specifiers, Cocoa sends
objectSpecifier messages to the objects to be returned. Therefore, for any class of object that is part of your containment hierarchy of scriptable objects, you must implement the
objectSpecifier method. This method is declared in
NSScriptObjectSpecifiers, a category on
NSObject that implements a version that just returns
For more information, including code examples, see “Object Specifiers.”
Use the Document Architecture
NSWindowController classes form the basic structure for the Cocoa document architecture. Together with the terminology defined in the Standard suite, these classes provide direct support for the standard AppleScript document scripting model, including classes such as
window. When you use these classes to implement a document-based application, that application automatically supports a number of scripting features.
For example, the
NSWindow classes are KVC-compliant for standard scriptable properties.
NSApplication provides methods for accessing the application's documents as an ordered list. The
NSDocument class provides support for the
save commands by implementing the
NSWindowScripting also implements default versions of these methods, which in many cases pass control to the window's document. It also implements methods for scriptable access to window attributes, such as the close box, title bar, and so on.
Applications that take advantage of Cocoa’s document architecture put themselves in a better position to support scripting generally. A document in Cocoa applications typically owns and manages one or more model objects of the application. It therefore provides a hub for scripted access to the model objects in your application, which are the ones that load and save data.
Table 3-1 lists Cocoa classes that correspond to AppleScript classes in the Standard suite, along with attributes and relationships (properties and elements) used by those classes.
Access the Text Suite
The Text suite defines terminology that allows scripts to request or select textual elements at different levels of granularity: character, word, paragraph, or entire body of text. The
NSTextStorage class, provided by the Application Kit, defines a corresponding set of methods for getting and setting scriptable properties of
To gain access to this text scripting support, use an
NSTextStorage object as the content for one of your scriptable classes. The TextEdit sample code (available at
<Xcode>/Examples/AppKit/TextEdit) demonstrates a scriptable application that supports text scripting, as well as scripting support for printing.
Table 3-2 lists Cocoa classes for working with text, along with attributes and relationships used by those classes.
Attributes (script term, if different)
font name (
attribute runs, characters, paragraphs, text, words