oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Variables Inside Cocoa Objects

by Brad Dominy

Last time we talked about the relationship between objects in Cocoa and in AppleScript. The object hierarchy -- the ordering of objects into classes and superclasses -- is important for creating a map between the scripting system and your application.

This map is contained in the scriptSuite file, an XML property list, located in the project's Resources folder. Along with the scriptSuite file, we also created a scriptTerminology file used to provide the syntax for the dialect you plan on supporting. Right now, as it has been pointed out to me, English is the only supported dialect, but the process will be the same if and when other dialects are added.

Accessing Variables Inside Cocoa Objects

Today we're looking at accessing the instance variables inside your Cocoa objects, and in the process we're going to explore part of the Core Text Suite that we get for free with Cocoa.

You may recall from the description of objects that I gave before, objects are units of code that contain variables used to hold information for the object and methods to perform some action associated with the object.

The variables are usually divided into two types, class variables and instance variables. Class variables are accessible by all objects of a given type or their subclasses (objects that inherit or are lower in the hierarchy). Instance variables are only for the particular object that was created, and the data they contain are unique to that object.

In our ScriptableDocApp from last time (you can download the project file here), we created a class called MyDocument that was a subclass of NSDocument. When we created our ScriptableAppDoc.scriptSuite file, we simply needed to establish the relationship between the application and the MyDocument class, as well as tell the scripting system what type of object we were making scriptable.

The result was that we could create new MyDocument objects and that they would respond to the same AppleScript commands available to the NSDocument class as supported in the NSCoreSuite. The scripting support for Cocoa applications has a really nice surprise in store for us, because once we make a class scriptable, accessing the instance variables of that class is simply a matter of providing the proper accessor methods.


Objective-C has a convention about getting and setting the value of an instance variable. The methods used to do this are referred to as accessor methods. The convention is that the method used to get the value of the instance variable should be named the same as the instance variable. So, if you had the following instance variable:

NSString *myString;

the method to get this value would be:

- (NSString)myString {
	return myString;

Its usage in your Objective-C code would be something like:

[myobject myString];

where myobject is an instance of your class, and you are sending it a myString message which invokes the myString method that returns the myString instance variable's value. Kind of weird, huh!?! The main thing to keep in mind is that usually the process of getting an instance variable's value is done through an accessor.

Now the second part of this task is setting the instance variable's value. The setter method follows the convention of naming it set<VariableName> with the first letter of the variable being capitalized. In our example above we would have:

- (void)setmyString: (NSString *)str {

	myString = str;

It's usage would be:

[myobject setmyString:@"hello"];

Now here we are passing a string to our method, which uses the local variable str declared in our method, binding it to the instance variable.

You do not have to follow these conventions and many programmers choose not to, but if you do, AppleScript will automatically be able to get and set the values of your instance variables. This convention of naming accessors is often times called key-value coding, and AppleScript and Cocoa use it often.

Key-Value Coding in Action

So let's see how this will work. Our plan is to add two instance variables to our MyDocument class from the ScriptableDocApp project we created last time. The NSTextSuite was included in ScriptableDocApp's scripting suite, but had no function since we did not have any classes that dealt with text. We are going to kill two birds with one stone by making our instance variables connect to a NSTextView object we add to our project in Interface Builder. We will use the other instance variable to hold the scriptable part of the NSTextView object, which is a NSTextStorage object. We will add the get and set accessor methods for the NSTextStorage instance variable, and finally add the relationship between the MyDocument and the NSTextStorage to our ScriptableDocApp.scriptSuite file.

Comment on this articleThe floor is open for questions and comments about AppleScript and Cocoa working together.
Post your comments

To begin, you can start with a new project and follow along or just download the completed project here. I am going to start with a new Cocoa document-based application in Project Builder and once again call It ScriptableDocApp. Once you've created the project, we need to enable AppleScript support for the application.

I had been doing this by editing the projects Info.plist, but several astute readers gave me some helpful hints on how to better do this. On the left vertical tab bar, by where the files are listed, there is a Targets tab. Click this and in the upper left area you will see the name of your project with a target next to it. Select this and the lower right region will change to a tab view that has a tab called Application Settings. Click on this and you should see a screen that starts with the section Basic Information.

This is where many of the items in the Info.plist are set, but there is not one for AppleScript in the Simple interface. Click on the Expert button on the right and you will see a list of keys. Click on "New Sibling" and change the name of the new item to "NSAppleScriptEnabled" and then double-click on in value column to the right of the NSAppleScriptEnabled key. Set its value to "YES" and then save the project. This will enable AppleScript once the project is built and will save that setting between builds and even if the project is cleaned.

Now, click back on the Files tab in the left vertical tab bar and you should be back where you started. Open up the Classes folder and click on the MyDocument.h file. We are going to add two instance variables and the two accessor class methods so make yours look like the following:

#import <Cocoa/Cocoa.h>

@interface MyDocument : NSDocument
    IBOutlet NSTextView *textView;
    NSTextStorage *textStorage;
- (NSTextStorage *)textStorage;
- (void)setTextStorage:(id)ts;


If this code is confusing, review Mike Beam's articles on the basics of Objective-C and Cocoa before going any further.

Click on the MyDocument.m file and scroll down past all of the other class methods, but before the @end marker. Paste in the following code:

- (NSTextStorage *)textStorage {
    NSLog(@"textStorage called");
    return textStorage;

- (void)setTextStorage:(id)ts {
    // ts can actually be a string or an attributed string.
    NSLog(@"setTextStorage called");
    if ([ts isKindOfClass:[NSAttributedString class]]) {
        [[self textStorage] replaceCharactersInRange:
        NSMakeRange(0, [[self textStorage] length]) withAttributedString:ts];
    } else {
        [[self textStorage] replaceCharactersInRange:
        NSMakeRange(0, [[self textStorage] length]) withString:ts];

In both of these methods, I have left in a call to NSLog, which can be used to debug and see what's going on during a programs execution. You can see the output in Project Builder when you build and run the application and it will help to see the key-value coding in action.

Pages: 1, 2

Next Pagearrow