Variables Inside Cocoa Objects
Pages: 1, 2
Now we have created our instance variables, but we still need to add a text item to the mix. If you look at the instance variables we added, you'll notice that one is declared as an IBOutlet with the class of NSTextView. The other is an NSTextStorage object. The NSTextView object we are going to add in Interface Builder, while the NSTextStorage object is going to be created automatically for us, but we will need to assign it to this instance variable in order to use it.
- First, on the left side, open the Resources folder and double-click on the
MyDocument.nibfile. This will launch Interface Builder and load your nib file. This file contains the Cocoa objects that make up yourMyDocumentclass. - If you look in the
MyDocument.nibwindow, you will see a blue cube called File's Owner. Click on this to highlight it and then switch to the Classes tab by clicking above on the Classes tab. - You should see the
MyDocumentclass as an item. Control-click on theMyDocumentname and you will get a contextual menu. Choose Add Outlet toMyDocument. - Change the name of
myOutlettotextViewand then change the type toNSTextView. - In the Cocoa panel, choose the item that looks like a text window and drag a
NSTextViewitem to your document's window. - Resize it to your liking.
- Switch back to the
MyDocument.nibwindow and click on the Instances tab. - Now, control-click on the blue cube and drag the blue line up to the
NSTextItemin the window above. - In the connections window, choose the
textViewitem and choose connect. - Save you document and quit out of Interface Builder.
Back in Project Builder, we first need to hookup our textStorage instance variable and then we need to add in our scriptSuite and scriptTerminology files.
To hook up textStorage, click on the MyDocument.m file and look for a method called windowControllerDidLoadNib. This is called once the window has been loaded by the application. By this point, we know our textView item, brought in as an IBOutlet from interface builder, will be available and we can ask it for its NSTextStorage object. We do this by adding the following code after the Add Code comment:
textStorage = [textView textStorage];
textStorage on the right side is a class method for NSTextView objects that returns that item's NSTextStorage item.
For the scriptSuite file it is much the same as last time, but we are going to add a section in the MyDocument section on the ToOneRelationships key. This will simply be the name of our instance variable and the type of object it is. The following snippet is what is added, but the full version follows:
Snippet for textStorage
<key>textStorage</key>
<dict>
<key>AppleEventCode</key>
<string>ctxt</string>
<key>ReadOnly</key>
<string>NO</string>
<key>Type</key>
<string>NSTextStorage</string>
</dict>
Full ScripableDocApp.scriptSuite
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>AppleEventCode</key>
<string>ScDA</string>
<key>Classes</key>
<dict>
<key>MyDocument</key>
<dict>
<key>AppleEventCode</key>
<string>docu</string>
<key>Superclass</key>
<string>NSCoreSuite.NSDocument</string>
<key>ToOneRelationships</key>
<dict>
<key>textStorage</key>
<dict>
<key>AppleEventCode</key>
<string>ctxt</string>
<key>ReadOnly</key>
<string>NO</string>
<key>Type</key>
<string>NSTextStorage</string>
</dict>
</dict>
</dict>
<key>NSApplication</key>
<dict>
<key>AppleEventCode</key>
<string>capp</string>
<key>Superclass</key>
<string>NSCoreSuite.NSApplication</string>
<key>ToManyRelationships</key>
<dict>
<key>orderedDocuments</key>
<dict>
<key>AppleEventCode</key>
<string>docu</string>
<key>Type</key>
<string>MyDocument</string>
</dict>
</dict>
</dict>
</dict>
<key>Name</key>
<string>ScriptableDocApp</string>
</dict>
</plist>
The ScriptableDocApp.scriptTerminology is exactly the same as last time and looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>Classes</key>
<dict>
<key>MyDocument</key>
<dict>
<key>Description</key>
<string>A ScriptableDocApp document.</string>
<key>Name</key>
<string>document</string>
<key>PluralName</key>
<string>documents</string>
</dict>
<key>NSApplication</key>
<dict>
<key>Description</key>
<string>ScriptableDocApp's top level scripting object.</string>
<key>Name</key>
<string>application</string>
<key>PluralName</key>
<string>applications</string>
</dict>
</dict>
<key>Description</key>
<string>ScriptableDocApp specific classes.</string>
<key>Name</key>
<string>ScriptableDocApp suite</string>
</dict>
</plist>
Add these files like we did last time, and then build and run the project.
AppleScript
All that work, but now we can do some really cool stuff.
Try this:
set out to ""
tell application "ScriptableDocApp"
activate
set w to make new document at the beginning of documents
set w to the first document
set the name of w to "first"
set y to count of documents
set z to get every document
set a to exists document 1
set the text of w to "hello"
set the font of the text of w to "Times"
set out to get the last character of the first word of the text of w
end tell
return out
Pretty cool, huh?! The Text Suite is available from ScriptableDocApp's scripting dictionary, so you can try out other cool things.
Next Time
Finishing up with the Core Suite and laying the foundation for custom suites. See you then.
Brad Dominy is the head of Neoki, LLC, a small web design firm located in Chicago, IL.
Return to the Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 5 of 5.
-
xml started to make a little sense, thanx
2002-05-08 13:06:50 psheldon [Reply | View]
Made alias to "Property List Editor". Took the patch of code about textStorage and inserted into a <dict> -</dict> tag open/close of some sort of recursively defined entity called, I imagine, a dictionary. I'm inventing language here to capture my working hypothesis at parsing xml.
I know the point wasn't a lecture in xml, but how easy it was to have applescript aware of object oriented programming abstractions with just a little bit of xml. Exciting.
I imagine dict stands for dictionary. Mike Beam introduced me to dictionaries in a column, but I was distressed that it sure didn't look like what I thought of as a dictionary from having one in paper or on cd. So, I think there is a pivotal concept of what is meant by a dictionary that might have to be taught informally by heuristic rather than formal definition of dictionary.
Perhaps we simply have the construct of list of lists. And list is the recursive old idea. But, I suspect a whole deal more. Property lists are known in the language of artificial intelligence. Frames are powerful in newtonscript because they can contain a list of anything. Property lists are important in list because they offer their own qualities in a structured way of thinking or having things think.
In short I am in great but happy confusion at seeing xml and dictionaries that I am on the verge of understanding, but that "confusion", I heard from wiser men than myself, is the characteristic feature of any new learning.
I tried to formally present Java to a teenager by hypothesizing sgml generalities of parsing(<tag> and </tag> embrace a recursively defined structure of which I don't know the name). I perhaps formed the mistake of thinking the teenager's quest for meaning had historical development that recapitulated that of a compiler. I think the teenager took off by himself, much as a compiler would, so I never got to experience my own historical development in understanding and meaning by getting beyond that simple hypothesis.
Now, however, I am excited by the outline appearance of an xml document congruent with the discovery that Adobe uses it as an authoring tool. I've used outliners as an authoring tool and also artificial intelligence of Maple.
Today I have wet my feet in dictionaries I don't quite know the end all meaning of. Maybe I'm happy I don't.
;-)
Thanx. Er, thanks. I went on, but better late than never.
;-)
-
ScriptableDocApp's path
2002-05-07 22:05:51 psheldon [Reply | View]
I had ScriptableDocApp in pathname twice. I put the project in a folder of same name, but PB did too. Then, PB wouldn't find executable even though it said the build was successful.
I renamed outer folder ScriptableDocApp1 and dragged ScriptableDocApp folder outside it and deleted ScriptableDocApp1. Then build complained until I cleaned and the program then ran.
I suspect I had run into some sort of path recursion confusion like I did on a Data General Advanced Operating System long ago. But, now that problem is gone.
The old applescript that launched the old ScriptableDocApp still did for awhile. If I had the newer ap running the script would talk to it.
I fiddled with deleting the old ap in its original location after copying it elsewhere and applescript "tracked" it. I can't recall all that I did to isolate how I fell into having applescript launch the newer version.
I fiddled with the applescript statements and augmented them so that I saw I could enter text and get it in the applescript.
Pretty cool.
If I read and do enough of this stuff and I'll think in cocoa.
;-)
-
Setter example
2002-04-13 17:22:14 shiny [Reply | View]
Hi,
Thanks for your timely article on AppleScript and Cocoa. I found your article very informative and enjoyable.
Just a minor point. Your setter example causes some problems such as memory leak. Your code
mystring = str;
should've been
[mystring autorelease]; or [mystring release];
mystring = [str copy]; or mystring = [str retain];
Thanks again for your article. I'm looking forward to reading your next one.
shin
-
Re: Setter example
2002-04-14 10:06:35 bdominy [Reply | View]
Hi Shin,
You are quite correct that one of your suggested means of releasing the existing mystring should have been used when making the new assignment to avoid memory leaks. I can only claim that I was trying to use the minimum amount of code to keep all of the concepts clear and I didn't want to introduce the issues concerning memory management and Objective-C. But, for completeness you are absolute correct and I will add this to future examples.
Brad






I see for this part you changed from a simple NSApplication to one based on NSDocument.
I am trying to have a simple little application using what you have outlined and set up a method which can be used via AppleScript using the accessors/etc, but just cannot seem to get things to work properly.
The dictionary shows the property, but when I try to use it in a script AppleScript sees it not as a property, but simply as a variable in the script.
So, how do you expose a set of accessors in a non-NSDocument derived application?