AppleScript in Cocoa
Volume Number: 18 (2002)
Issue Number: 05
Column Tag: AppleScript in Cocoa
It's Now Easier to Support AppleScript Suites in Cocoa
by Don Briggs email@example.com
AppleScript Studio is now available to developers. This product will open Mac OS X development to many more people, and they will build applications relying on AppleScript. If their applications are to interoperate with yours, your Cocoa applications and their underlying frameworks must also support AppleScript.
This article is for Cocoa Objective-C developers. It will review the concepts and techniques necessary to implement AppleScript support. It will show the steps necessary to revise an existing example to support AppleScript. It introduces a new application for composing AppleScript suites —SuiteModeler. A compressed disk image
EZCocoaAppleScript.dmg.gz is available for download at: http://homepage.mac.com/donbriggs/FileSharing.html
The disk image contains:
- this document as EZCocoaAppleScript.rtfd;
- KVC_Demo —a simple Project Builder tool project that demonstrates Key-Value Coding;
- DotSuite.scriptDocument, a SuiteModeler document (a wrapper/directory) containing the suite definition and suite terminology files for a Cocoa AppleScript suite, and a directory of ‘naive' Objective-C files to support the suite.
- ScriptableDotView —the example application we will build in this article as a Project Builder project;
- sample output documents (bigRed.dot, littleBlue.dot) in XML form; and
- a test script that drives our ScriptableDotView application.
In this article, we will compose an AppleScript suite from scratch using SuiteModeler. This suite will serve as a statement of requirements, and the Objective-C files that SuiteModeler emits will serve as a starting point for our implementation. From these Objective-C files we will implement the classes and commands of the suite. We will build the document-based application, ScriptableDotView, that supports the suite. To emphasize KVC, we will also employ it to provide XML persistence for our documents in just a few lines of code. We will repackage the data-handling classes of our suite as a reusable framework. Finally, we will test our implementation using AppleScript.
The reader is invited to download SuiteModeler version 1.7.2 (or later) and run it in Demo mode. You need not buy a license to follow this article —the disk image provides all the required output files. SuiteModeler's Demo mode also permits you to inspect other suites and to check them for conflicts (see below). In licensed mode, SuiteModeler will save the suites you compose.
Suites were Hard to Compose
Nominally we use Apple's "PropertyList Editor" application
to compose Cocoa suites. It supports the property list format, but the following difficulties remain:
We need to produce two files, the *.suiteScript and *.scriptTerminology. Each provides its own "projection" of the underlying classes, but these projections are not "orthogonal"—the two files must maintain a nontrivial correspondence. But "PropertyList Editor" edits each file separately.
There are lots of key words, and their values must obey rules. You must read and apply
Some symbols refer to others, but unresolved references are not immediately obvious.
There are some annoying or confusing aspects of the Cocoa documentation: we find two meanings for the word "Property," for instance.
Some entries are generic and could be "calculated" from others, but "PropertyList Editor" does not provide such help —it's a general application.
Finally, when inspecting a suite (or rather, one half of a suite) in "PropertyList Editor," much of the text we see amounts to repeated key words.
In short, we could use some better tooling.
Suites were Hard to Support
Given a composed suite, the developer hoping to support AppleScript in Cocoa must make sure the Objective-C classes correspond to the suite. In the phrase often used by College-level Math texts, the process is "tedious but straight-forward." And "by inspection" —those same texts also say "by inspection" a lot. Admittedly, your second suite will be much easier, but your first one will require close reading of several lengthy documents. Wouldn't it be nice if your first suite were easy and it "just worked"?
Suites were Hard to Debug — Conflicts!
Even after a script compiles, it may not run as expected; the trouble often lies in the relationships of Apple Event Codes and external names. A given code can associate with multiple external names, but a given external name must associate with a unique code. If your suite matches an Apple Event Code with an external name that already exists in another suite loaded at run-time (NSCoreSuite and NSTextSuite come to mind), scripts written against your suite may crash or yield unexpected results. Such conflicts have stumped experts —and for good reason. To the author's present knowledge, this "gotcha" remains undocumented by Apple. (Greg Titus of OmniGroup for pointed out this "gotcha" to the author. Thanks, Greg.)
Composing and Supporting Cocoa Suites Just Got Easier
SuiteModeler is available as a demo at
You are invited to download it and use it to inspect Cocoa suites. The download site provides a screenshot of the suite from the Create application from Stone Design.
The Cocoa suites you compose will often build on NSCoreSuite and NSTextSuite. You'll find these among SuiteModeler's "Open Recent" menu items. When using SuiteModeler to inspect a suite or check one for conflicts, be sure to open any suites it depends on.
Background on AppleScript in Cocoa
To implement AppleScript support in Cocoa, you need to know about two important supporting concepts —the design pattern known as Model-View-Controller (MVC), and the technique known as Key-Value Coding (KVC). If you have not seen these Cocoa documents before,
this article will introduce you to the main ideas we need to understand to support AppleScript. We also need to focus on document-based applications as described in
You will find that when we use NSApplication and NSDocument, we get lots of AppleScript support for free.
Regular readers of MacTech and those long interested in AppleScript for Cocoa already know of Andrew Stone's earlier article, "Adding AppleScript Support to Cocoa Apps."
There, Andrew discussed MVC, KVC, and AppleScript support in the Sketch example. Andrew's article also showed us how to add a "Save as AppleScript..." capability to Sketch.
Sketch is quite a large example, and presents its AppleScript suite with little explanation. A reader previously unfamiliar with Sketch might find it daunting. This article takes a bare-bones approach to building a suite —the ratio of explanation to code is quite different. We start from a simpler example, DotView, which is found at file:///Developer/Examples/AppKit/DotView.
Newcomers might compare DotView and Sketch for size and complexity, then take a relaxing deep breath.
Model-View-Controller — MVC
The Model-View-Controller design pattern comes to us from the Smalltalk tradition. MVC suggests that we partition our objects into those that treat the "real data" —the "Model" part; those that provide a human interface to the data —the "View"; and other stuff necessary to glue the Model and View together —the "Controller" part.
Generally, design patterns identify commonly occurring archetypes of interoperating components. They bear "prior knowledge" at the conceptual and architectural level. The main benefit of following the MVC design pattern is the reusability of the components we build.
The Cocoa frameworks were designed to support MVC. Using Cocoa, we find we can often make the "Model" part into a stand-alone framework and use it again for other purposes. Our "Model" frameworks commonly build on the Foundation framework —Foundation comprises mostly "Model" classes that encapsulate "real data." The AppKit framework provides classes that support the "View" and "Controller" parts. Often, we can get most or all the "View" part from Interface Builder. For ScriptableDotView, Cocoa provides much of the Controller part with no extra code. If you avoid storing "model" information in "view" objects (for instance, don't store a boolean in a button's state), you'll find that the Cocoa frameworks provide a natural basis for the MVC design pattern. When we add AppleScript capability, we add a powerful way to control the "Model" part.
Key-Value Coding —KVC
Key-Value Coding amounts a simple discipline that matches the declaration of an instance variable to the declarations of its getter and setter methods. When we follow those rules in a class for an instance variable, we implement KVC in that class for that variable. Given an instance variable of primitive type ( BOOL, char, short, unichar, int, float, double, ...) or struct (NSRange, NSPoint, NSSIze, NSRect, ... ) we have as a declaration
type _xyz; // Let type be one of:
// BOOL, char, short, unichar, int, float, double, ..., NSRange, NSPoint, NSSIze,
// NSRect, ... and as accessors
Given an instance variable that is an object, we have as a declaration
and as accessors
You may neglect the underscore prefix in the name of the instance variable, but then you should change the name of the argument in the corresponding setter method.
The KVC_Demo project is a simple one-class tool project that shows KVC at work. You can use KVC to reduce the complexity of your code, independent of AppleScript support. The Cocoa documentation on scripting recommends that you "define the set of keys each scriptable class supports." The author suggests that you use class methods to provide collections of related keys. In KVC_Demo, the class method +[ModelClass kvcKeys] provides such an array of keys.
Copy the example DotView project to a convenient place, compile it, run it, and marvel at it. The DotView example application shows us how a subclass of NSView can respond to a mouse click with a drawing operation. The project has a single class, DotView—pristine simplicity. But with apologies to DotView's author, Professor Ozer*, the author points out that DotView does not follow MVC nor does it support KVC. Newcomers might breathe a sigh of relief now. If presently your code falls short too, you'll find yourselves in fine company.
(*Ali Ozer only professes to be the head of the AppKit —he is the only remaining original engineer from the first four that worked on NeXTSTEP in the late eighties.)
Consider the class DotView from the perspective of MVC. It descends from NSView but has instance variables and accessor methods for the only "real data" of the application. It's both the "View" and the "Model." DotView has no need for a "Controller" part, then. We'll revise the project along the lines of MVC.
As for KVC, we see that there are instance variables named "color" and "radius" with the accessors
But these method signatures do not support KVC —each "setter" method should take as its single argument a variable of the same type as its associated instance variable. To support KVC, we need instead
We'll fix that, too.
On to ScriptableDotView.app
Let us imagine that we work as developers for the company called "My Great Software, Inc." and that the prototype application, DotView, has successfully promoted an idea for a marketable application. Marketing loves it, Management is committed to it, and now we have to deliver on its promise. ScriptableDotView will be our product, an industrial-strength revision of the prototype. A high-level meeting has produced a set of requirements. (We always need requirements. How else will we know when we're done?)
 ScriptableDotView reproduces the look and feel of DotView.
 ScriptableDotView has just one kind of document, and it saves the state of a "Dot" —its radius, position, and color.
 The document must persist in XML form. Management loves buzz-word compliance. (XML really is useful, though.)
 The document must permit AppleScript access to its dot's radius, position, and color.
 The document must support an AppleScript command, ReCenter, to place the dot in the center of the view area.
 And Marketing suspects that a few other related applications could follow on, so we should encapsulate the "real data" in a framework that we can use again.
An Internal Requirement
The ReCenter command is the simplest kind of command; it takes no arguments and returns void. While we're exploring AppleScript support, it seems prudent to demonstrate support for a command that takes an argument and returns a value. We'll add a command to the Dot class that does something simple and clearly useless to ScriptableDotView: it will take a string argument and return a string with the same characters in the opposite order. We'll spend just a few minutes under Management's radar on this, but this exercise will improve our confidence in supporting AppleScript. We add to our requirements:
 The Dot class will temporarily support the Reverse command (a command with one argument and a return value).
At the core of things, we have the concept of the dot, the "real data" of the application—the "Model" in an abstract sense. We'll have a class, Dot, to manage the dot's radius, position, and color. Also, we'll have a subclass of NSDocument, DotDocument, to manage a single instance of Dot. The separation between the dot and its document may seem contrived, but often a document manages a collection of model objects, but here, we have just the single element. (Often, a descendent of NSDocument acts as a sort of Model-Controller. Contrast this to NSWindowController, which is a kind of View-Controller.) As for the rest of the "Controller" part, we could conceivably subclass NSDocumentController and NSWindowController, but for the sake of expediency, we'll force into the DotDocument class any leftover model-controller methods we need. We'll package the Dot and DotDocument classes in a scriptable framework, , to provide the "Model" and "Controller" parts of our MVC design. The "View" part must derive from the prototype to preserve its look and feel. Here, this means that we can copy the *.nib file of the prototype and make a few modifications. As a novel departure, we will start with an AppleScript suite as a statement of requirements and then drive the implementation to support our suite.
Our suite, DotSuite is conceptually very simple: it has two classes: an instance of the DotDocument class serves as a container for an instance of the Dot class. DotDocument has just one read-only attribute, its dot. Dot has four attributes: its x and y positions, its radius and its color. DotSuite has the two Commands, but no Enumerations or Synonyms.
Ideally, Dot should have one attribute of type NSPoint instead of two attributes of type float, the x and y positions. However, as presently documented, Cocoa AppleScript suites support only primitives (BOOL, short, int, float, ...) and objects as attributes. We look forward to support for structs such as NSPoint and NSRect. Curiously, if you examine NSCoreSuite, you'll find a dictionary called ValueTypes with one entry pairing the key QDRect with the string value qdrt. Also, the NSWindow class has a property named boundsAsQDRect and type NSData. As of Mac OS 10.1.3, the author has found no documentation explaining these entries. We'll follow the lead of the Sketch example and proceed with the pair of floats (as instances of NSNumber).
The AppleScript Suite —DotSuite
To compose this suite, launch SuiteModeler and edit its empty suite document. The screen shots below show what to type in. In the "Preferences" panel, choose the "Cocoa/E-R/EOModeler" nomenclature to see these tab labels. SuiteModeler combines the definition and terminology in one document and presents it as a tree of table views. Wherever a node has multiple children, the children appear as tabs in a tab view. The root of the tree, the suite itself, is a special case and appears as a the "Suite" tab among its children. Also, an extra "Summary" tab provides a flattened summary, useful for sorting out more complicated suites and finding conflicts.
The Suite Itself
The suite itself has an internal and an external name, an Apple Event code, and a description. Fill in these four fields as shown. (Throughout this exercise, we will neglect entries in the description fields. SuiteModeler makes it easy to add them, and they can be extremely useful to the AppleScript authors who will incorporate your application in their scripts. However, descriptions are the least of our immediate concerns.)
Apple Event code entries always have four characters, and SuiteModeler enforces that constraint. Apple has reserved the space of codes comprising all combinations of four lower-case letters, so always use at least one upper-case letter in your codes. (Beware: if the trailing characters are spaces, that fact won't be apparent in "PropertyList Editor" unless you select the entry.)
We start with the two Commands. In the "Commands" tab, use the upper "+" button to add thwo entries. Their names appear initially as MyCommand, and MyCommand_1. Enter the values for the fields in the upper table as shown (use any string for the descriptions). Rename them and enter the other fields as shown. Notice that SuiteModeler generates some fields for you: given a name, it guesses the external name. Given an external name, it guesses the plural and sometimes, it can correctly guess the appropriate Apple Event Code value.
The ReCenter command takes no arguments and yields no result. It simply re-centers the dot in the view and serves as an example of the simplest kind of command. With the Reverse command selected, use the "+" button in the lower table to add its string argument as shown. The Reverse takes a string as an argument and returns a string of the same characters in the opposite order (just to demonstrate an AppleScript command with an argument and a return value).
Our suite has two classes. In the "Classes" tab, use the upper "+" button to add two entries. They appear with MyClass and MyClass_1 in the "name" column, again with default entries in the other columns.
The DotDocument Class
In the first entry, type in DotDocument in the "name" column. SuiteModeler generates its external name and plural, so these entries are in gray. Type in docu for its Apple Event Code, and NSCoreSuite.NSDocument as its superclass. Here, we're using the code docu from the core suite, so it's all lower-case. The superclass entry appears in red denoting an unresolved reference. (To resolve the reference, open the NSCoreSuite from the "Open Recent" menu. This entry then appears in black.) Type in an entry for the description. With the DotDocument row still selected, choose the "Attributes" tab in the lower half of the split view. Then use the lower "+" button to add an attribute. Set its name to dot, its type to Dot, its code to xDot, and set the "[r/o]" or Read-Only column entry to Y or y. SuiteModeler will complete the entry. SuiteModeler constrains the entries for the sex and number columns in a similar way —just type in the first letter of your choice.
The Dot Class
The entries for the Dot class follow from the screen shot. (Once you've typed in its name, the reference to it in the DotDocument class should appear in black.) Notice that its external name, dot, appears in blue (multiple references), and its code, xDot, appears in grey (default) to indicate that all (here, both) items with the same external name have the same code.
Tying Classes to Commands
For each of the two classes, add supported commands as shown. Had we not defined these commands first in the "Commands" tab, their names would have appeared in red—perhaps a little alarming for an introduction. Again, given the name for a supported command, SuiteModeler calculates a method name.
The headers of the columns of all the table views in SuiteModeler provide tool tip support. Each column's tool tip associates a key with the text from the corresponding tables of the documentation in
The exception is the "ext. name" column. It shows the synthetic "HumanReadableName" instead of "Name," which is the key associated with the "name" column.
Conflicts —a Demonstration
As an experiment, temporarily make a conflict of codes and external names. Change the code for the dot class from xDot to yDot then switch to the "Summary" tab. You'll see that suddenly the codes and external names involved in the conflict appear in red. If you try to save the suite document in such a state, SuiteModeler will warn you. Change it back to xDot.
Some readers may choose to complete this exercise successfully, then build in a conflict and explore the consequences.
If you've not bought a license, use the result supplied. Otherwise, save the result as DotSuite, using the default choice, document wrapper, for the output file format. The wrapper contains the definition and terminology files. Check it against the version supplied.
You could also reproduce the work in the "PropertyList Editor" application, but you'll have to read the documentation more carefully to produce a working suite that way. Choose a non-trivial existing suite, say NSCoreSuite to compare SuiteModeler and "PropertyList Editor." You'll find the SuiteModeler presentation more compact and unified (after all —using "PropertyList Editor," you have to open two documents, the definition and the terminology). Certainly, when you compose your own suite, SuiteModeler's validation, automatic generation of default values, and cross-referencing features will save you some headaches.
The ‘Naive' Objective-C Files
SuiteModeler also emits a directory of Objective-C files when it saves a suite document. Open all the Objective-C files in the document wrapper now. Each class in your suite results in a *.h and a *.m file. A single *.h file declares any enumerations in the suite. For each class, it provides instance variables and accessors for each attribute/property and property/element (only the "getter" methods for the read-only cases). It also declares and provides a base implementation for each supported command, declaring and extracting any command arguments. It also declares and implements a class method that provides an array of keys useful for KVC. It also provides some support for object specifier methods.
Implementation —Step by Step
SuiteModeler will not emit all the code necessary to implement your suite, and the class files will likely not compile as emitted. In each case, you'll need to add or modify a few lines to import the parent class, and to import or declare any other classes referenced (perhaps using "@class" in the *h files). You may need to import these from your own frameworks. However, SuiteModeler has saved you lots of typing. As a developer, you must provide the underlying logic specific to your "Model" —that's why "My Great Software, Inc." pays you the big bucks. For each class, Dot and DotDocument, we explain the few lines we modify to compile the naive file. Then we add categories of "Model" logic to each.
First we'll build and test a simple application. Then we will repackage it by moving two classes into a framework. We will also make the framework scriptable. We'll re-compile and test the repackaged code. Then we'll drive the resulting compiled application with an AppleScript suite.
Start with a Cocoa Document-based project. It provides a generic "MyDocument" class—keep it. Add the Dot and DotDocument files to the "Classes" group, "by copy" from the suite document wrapper. We'll move them into a framework later. For the methods below, find their implementations in the completed project.
In this exercise, we will rely on several categories in separate files. A category encapsulates a group of related methods. The author hopes that by isolating these categories in separate files, the reader will find it easier to track differences using FileMerge. (The XML methods for NSDictionary can prove generally useful.) Otherwise, this exercise takes the notion of categories and protocols perhaps a bit too far.
Initial Details —Imports and Declarations
just before the "@interface ..." line.
 In DotDocument.h, comment out the line
We get reference to that class when we import the <Cocoa> framework.
 Also in DotDocument.h, add
just before the "@interface ..." line.
 In DotDocument.m, import the Dot class. Add
just after the existing import.
 in Dot.m, import DotDocument.h similarly.
The changes so far should permit you to compile the ‘naive' files, but the compiler will warn about unused variables.
Add a Category of XML Methods to NSDictionary
Add to your projects by copy the files NSDictionary+XMLMethods.h and *m (provided in the ScriptableDotView project). You may find this category generally useful. See Brian Webster's post on the OmniGroup Cocoa Dev list, www.omnigroup.com/mailman/archive/macosx-dev/2001-January/008625.html
One might reasonably expect Cocoa API for this. As things stand, we drop down into Carbon.
Repackage the MyDocument Methods as a Category
Project Builder provides some Objective-C code in the generic "MyDocument" class. Convert the MyDocument class to be the DotDocument+Subclassing category. Rename the *.h and *m files, change the import statement in the *.m file, and change the @interface and @implementation lines to support the category. They become
@interface DotDocument (Subclassing)
@implementation DotDocument (Subclassing)
(and delete the pair of curly braces in the *.h file). Also in the *.m file, change the windowNibName method to return @"DotDocument".
Augment DotDocument+Subclassing For XML Persistence
In the *.m file, import NSDictionary+XMLMethods.h and Dot.h. In the methods
add the few lines necessary to provide XML persistence. Notice that KVC makes this really compact. Compare with SKTDrawDocument in the Sketch example. Sketch resorts to the methods -[SKTGraphic propertyListRepresentation] and +[SKTGraphic graphicWithPropertyListRepresentation] and their overriding implementations in the subclasses of SKTGraphic. If we had comparable subclasses here, we would only need to override the +kvcKeys method in each subclass (assuming we had already written the matching get and set methods anyway). Remember that any code you don't have to write is code you don't have to debug, either.
Add DotDocument+ModelControlling as a Category
This category comprises two methods. One writes "Model" information to the "View," and the other writes "View" information to "Model." Such a pair of methods often proves useful. Import the DotDocument+ModelControlling.h category.
Add the NSView+DotViewing Protocol
This protocol declares one method. It will become part of the framework. The application will have a DotView class that conforms to it.
Add Model-Controller Instance Variables and Logic to DotDocument
In DotDocument.h add these instance variables
IBOutlet NSView *_view;
IBOutlet NSSlider *_slider;
IBOutlet NSColorWell *_colorWell;
and declare these methods:
The viewAction method responds to user interactions—mouse clicks and drags, and setting the color—and passes the information to the document, which sends it to the model. The modelChanged method signals the "View" that it must re-draw to reflect changes in the "Model." In Document.m, import the DotDocument+ModelControlling.h category. It comprises two methods. One writes "Model" information to the "View," and the other writes "View" information to the "Model." In this class, they're both empty—we'll override them in DotDocument to do useful work. Add the awakeFromNib method to initialize the "View." Find the implementations for these methods in the completed project. Add an init method that initializes the document's instance of the Dot class. Add the awakeFromNib method to initialize the "View."
Augment the Class Implementations with Custom "Model Logic"
Declare and implement the initWithDocument: method, and import "DotDocument.h". DotDocument's handleReCenterScriptCommand: and Dot's handleReverseScriptCommand: both require few-liner modifications. We can't save NSColor in property list form directly. As in the Sketch example, we'll have to archive NSColor as NSData. We're not free to replace the naive color accessors —AppleScript needs them—so we'll supply two more to access the color attribute as archived NSData. Be sure to change colorKey to colorDataKey so our kvcKeys method can support XML persistence. We'll come to the remaining new instance variable and the initializer later.
Steal Your Interface
Open the MainMenu.nib document of the DotView example and copy its Window component (it has the view, color well, and slider). Open your project's MyDocument.nib file, delete its Window component and replace it with the one from DotView. Drag the DotDocument.h file from Project Builder's files pane onto the MyDocument panel, so Interface Builder can parse the file. Set the File's Owner to be DotDocument. Delete MyDocument from your nib. Disconnect the actions for the slider and color well, and connect them to the File's Owner, choosing the viewAction: method. Save the result as DotDocument.nib.
Adjustments for Fit and Finish
Choose your project's "Targets" tab. In the "Application Settings" tab and using the "Expert" settings, set the document class to be DotDocument and set the file extension to be dot. Choose the "simple" settings and set the document's extension to dot.
The application should compile and launch after you have made these changes. It should be able to save and open its documents in XML form.
Make it Scriptable
Under the application target's application settings tab, choose the "expert" settings and add a new sibling called NSAppleScriptEnabled. Set its value to the string YES. Add to the Resources group the files DotSuite.scriptSuite and DotSuite.scriptTerminology from the DotSuite.suiteDocument file wrapper provided, using the "by copy" option. Localize the terminology file (select it in the Files pane and "Show Info"). Be sure that these files are checked as part of the application target. Recompile. Now, Script Editor should be able to browse to your project's "build" directory and open your application's dictionary. Also, the script provided should properly drive your application.
One More Step —Repackage the "Model" classes as a Framework
Refer to the article http://www.cocoadevcentral.com/tutorials/
"Frameworks Within the App Bundle" by Brian Christiansen, Cocoa Dev Central
Following the article, set the framework's installation location to the path:
and add the linker flag
as detailed there.
From the "Project" menu, choose "new target." Choose its type to be Cocoa framework. Set the name of the framework target to be Dot. In the Target pane, set the Dot target to be ‘under' ScriptableDotView (that is, to make ScriptableDotView, you must first have made Dot. )
In the File pane, add a new Group called and select it. Move the NSView+DotViewing protocol and the Dot and DotDocument classes into the new group. Remove them from the application target and add them to the framework target. Be sure to set those headers to "Public." Similarly, move the DotSuite.scriptSuite and DotSuite.scriptTerminology files to the framework. You'll also need to drag the Dot.framework element in the "Products" group in the Files pane to the application target's "Files & Build Phases" tab's "Frameworks & Libraries" fields.
Compile and run the application. If it fails, compare your project against the supplied ScriptableDotView project. You should be able to verify that the requirements have been met.
We've used the SuiteModeler application to compose a Cocoa AppleScript suite as an expression of requirements. We've developed a framework and application on it that support our AppleScript suite, starting from the Objective-C files SuiteModeler emitted, adjusting only the imports and declares, and adding just a few lines of "Model" logic. We have used Key-Value Coding both in the support of our suite and to simplify XML persistence of our document-based application. We have used AppleScript to test our implementation. Readers can now build their own script-enabled Cocoa applications and frameworks more easily.