TweetFollow Us on Twitter

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 donbriggs@mac.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.

Overview

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.

Introducing SuiteModeler

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

file:///Developer/Applications/PropertyListEditor.app

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

file:///Developer/Documentation/Cocoa/ProgrammingTopics/Scripting

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 http://homepage.mac.com/donbriggs/FileSharing.html

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,

file:///Developer/Documentation/Cocoa/ProgrammingTopics/AppDesign/AppDesign.1.html

file:///Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/KeyValueCoding/index.html

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

file:///Developer/Documentation/Cocoa/ProgrammingTopics/AppDesign/AppDesign.d.html

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." http://www.mactech.com/articles/mactech/Vol.16/16.07/AppleScripttoCocoa/

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
   -(type)xyz;
   -(void)setXyz: (type)xyz;

Given an instance variable that is an object, we have as a declaration

   MyClass *_abc;
and as accessors
   -(MyClass*)abc;
   -(void)setAbc: (MyClass*)abc;

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.

DotView Revisited

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

   - (IBAction)setRadius:(id)sender;
   - (IBAction)setColor:(id)sender;

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

   -(float)radius;
   -(void)setRadius: (float)radius;
and
   -(NSColor*)color;
   -(void)setColor: (NSColor*)color;
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?)

Requirements

    [0] ScriptableDotView reproduces the look and feel of DotView.

    [1] ScriptableDotView has just one kind of document, and it saves the state of a "Dot" —its radius, position, and color.

    [2] The document must persist in XML form. Management loves buzz-word compliance. (XML really is useful, though.)

    [3] The document must permit AppleScript access to its dot's radius, position, and color.

    [4] The document must support an AppleScript command, ReCenter, to place the dot in the center of the view area.

    [5] 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:

    [6] The Dot class will temporarily support the Reverse command (a command with one argument and a return value).

Design Overview

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.

DotSuite

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.)

pastedGraphic.tiff ¬

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.)

Commands

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.

1__#$!@%!#__pastedGraphic.tiff ¬

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).

Classes

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.

2__#$!@%!#__pastedGraphic.tiff ¬

3__#$!@%!#__pastedGraphic.tiff ¬

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.

4__#$!@%!#__pastedGraphic.tiff ¬
5__#$!@%!#__pastedGraphic.tiff ¬

Tool Tips

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

file:///Developer/Documentation/Cocoa/ProgrammingTopics/Scripting/SuiteDefs

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.

6__#$!@%!#__pastedGraphic.tiff ¬

Some readers may choose to complete this exercise successfully, then build in a conflict and explore the consequences.

Save

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

    [1] In Dot.h, add

       @class DotDocument;
    

    just before the "@interface ..." line.

    [2] In DotDocument.h, comment out the line

       #import "NSDocument.h" 
    

    We get reference to that class when we import the <Cocoa> framework.

    [3] Also in DotDocument.h, add

       @class Dot;
    

    just before the "@interface ..." line.

    [4] In DotDocument.m, import the Dot class. Add

       #import "Dot.h"
    

    just after the existing import.

    [5] 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) 

and

   @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

   dataRepresentationOfType:

and

   loadDataRepresentation:ofType:

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:

   -(IBAction)viewAction: (id)sender;
   -(void)modelChanged;

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.

First Test

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:

   @executable_path/../Frameworks

and add the linker flag

   -seg1addr 0x10000000

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.

QED

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.

Conclusion

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.


 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Fresh From the Land Down Under – The Tou...
After a two week hiatus, we are back with another episode of The TouchArcade Show. Eli is fresh off his trip to Australia, which according to him is very similar to America but more upside down. Also kangaroos all over. Other topics this week... | Read more »
TouchArcade Game of the Week: ‘Dungeon T...
I’m a little conflicted on this week’s pick. Pretty much everyone knows the legend of Dungeon Raid, the match-3 RPG hybrid that took the world by storm way back in 2011. Everyone at the time was obsessed with it, but for whatever reason the... | Read more »
SwitchArcade Round-Up: Reviews Featuring...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for July 19th, 2024. In today’s article, we finish up the week with the unusual appearance of a review. I’ve spent my time with Hot Lap Racing, and I’m ready to give my verdict. After... | Read more »
Draknek Interview: Alan Hazelden on Thin...
Ever since I played my first release from Draknek & Friends years ago, I knew I wanted to sit down with Alan Hazelden and chat about the team, puzzle games, and much more. | Read more »
The Latest ‘Marvel Snap’ OTA Update Buff...
I don’t know about all of you, my fellow Marvel Snap (Free) players, but these days when I see a balance update I find myself clenching my… teeth and bracing for the impact to my decks. They’ve been pretty spicy of late, after all. How will the... | Read more »
‘Honkai Star Rail’ Version 2.4 “Finest D...
HoYoverse just announced the Honkai Star Rail (Free) version 2.4 “Finest Duel Under the Pristine Blue" update alongside a surprising collaboration. Honkai Star Rail 2.4 follows the 2.3 “Farewell, Penacony" update. Read about that here. | Read more »
‘Vampire Survivors+’ on Apple Arcade Wil...
Earlier this month, Apple revealed that poncle’s excellent Vampire Survivors+ () would be heading to Apple Arcade as a new App Store Great. I reached out to poncle to check in on the DLC for Vampire Survivors+ because only the first two DLCs were... | Read more »
Homerun Clash 2: Legends Derby opens for...
Since launching in 2018, Homerun Clash has performed admirably for HAEGIN, racking up 12 million players all eager to prove they could be the next baseball champions. Well, the title will soon be up for grabs again, as Homerun Clash 2: Legends... | Read more »
‘Neverness to Everness’ Is a Free To Pla...
Perfect World Games and Hotta Studio (Tower of Fantasy) announced a new free to play open world RPG in the form of Neverness to Everness a few days ago (via Gematsu). Neverness to Everness has an urban setting, and the two reveal trailers for it... | Read more »
Meditative Puzzler ‘Ouros’ Coming to iOS...
Ouros is a mediative puzzle game from developer Michael Kamm that launched on PC just a couple of months back, and today it has been revealed that the title is now heading to iOS and Android devices next month. Which is good news I say because this... | Read more »

Price Scanner via MacPrices.net

Amazon is still selling 16-inch MacBook Pros...
Prime Day in July is over, but Amazon is still selling 16-inch Apple MacBook Pros for $500-$600 off MSRP. Shipping is free. These are the lowest prices available this weekend for new 16″ Apple... Read more
Walmart continues to sell clearance 13-inch M...
Walmart continues to offer clearance, but new, Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) online for $699, $300 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBooks... Read more
Apple is offering steep discounts, up to $600...
Apple has standard-configuration 16″ M3 Max MacBook Pros available, Certified Refurbished, starting at $2969 and ranging up to $600 off MSRP. Each model features a new outer case, shipping is free,... Read more
Save up to $480 with these 14-inch M3 Pro/M3...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more
Amazon has clearance 9th-generation WiFi iPad...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Apple is offering a $50 discount on 2nd-gener...
Apple has Certified Refurbished White and Midnight HomePods available for $249, Certified Refurbished. That’s $50 off MSRP and the lowest price currently available for a full-size Apple HomePod today... Read more
The latest MacBook Pro sale at Amazon: 16-inc...
Amazon is offering instant discounts on 16″ M3 Pro and 16″ M3 Max MacBook Pros ranging up to $400 off MSRP as part of their early July 4th sale. Shipping is free. These are the lowest prices... Read more
14-inch M3 Pro MacBook Pros with 36GB of RAM...
B&H Photo has 14″ M3 Pro MacBook Pros with 36GB of RAM and 512GB or 1TB SSDs in stock today and on sale for $200 off Apple’s MSRP, each including free 1-2 day shipping: – 14″ M3 Pro MacBook Pro (... Read more
14-inch M3 MacBook Pros with 16GB of RAM on s...
B&H Photo has 14″ M3 MacBook Pros with 16GB of RAM and 512GB or 1TB SSDs in stock today and on sale for $150-$200 off Apple’s MSRP, each including free 1-2 day shipping: – 14″ M3 MacBook Pro (... Read more
Amazon is offering $170-$200 discounts on new...
Amazon is offering a $170-$200 discount on every configuration and color of Apple’s M3-powered 15″ MacBook Airs. Prices start at $1129 for models with 8GB of RAM and 256GB of storage: – 15″ M3... Read more

Jobs Board

*Apple* Systems Engineer - Chenega Corporati...
…LLC,** a **Chenega Professional Services** ' company, is looking for a ** Apple Systems Engineer** to support the Information Technology Operations and Maintenance Read more
Solutions Engineer - *Apple* - SHI (United...
**Job Summary** An Apple Solution Engineer's primary role is tosupport SHI customers in their efforts to select, deploy, and manage Apple operating systems and Read more
*Apple* / Mac Administrator - JAMF Pro - Ame...
Amentum is seeking an ** Apple / Mac Administrator - JAMF Pro** to provide support with the Apple Ecosystem to include hardware and software to join our team and Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.