Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2004-430
$eventId
ID of event: wwdc2004
$eventContentId
ID of session without event part: 430
$eventShortId
Shortened ID of event: wwdc04
$year
Year of session: 2004
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC04 • Session 430

Advances in Cocoa Scripting

Application • 55:59

Automation is an essential feature for any Mac OS X application and Cocoa includes powerful support for easily making your application scriptable. This session will include a brief overview of Cocoa scripting, and then present detailed information about upcoming improvements, including improved error handling, improved text support, and adoption of the latest key-value coding features. This is an intermediate-level session.

Speaker: Mark Piccirelli

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it may have transcription errors.

Good afternoon. My name is Mark Petrelli. I'm an engineer in the Cocoa Frameworks group. Tiger is going to include a lot of new Cocoa scripting features. And the focus of all these is to make it as easy as possible for you to implement great scriptability. The prerequisites for this talk, if you've already done a lot of basic Cocoa programming, you'll find out how to add scriptability to your existing applications. If you've been working with Cocoa scripting already, you'll find out what's new in Tiger, there's a bunch. And if so far you've been programming in Carbon land, but you know a bunch about scriptability, this will be a good opportunity for you to get a sort of a feel for how Cocoa differs.

Today I'll be specifically talking about the new SDF file format that Cocoa supports for you to declare your scriptability. I'll go into a good bit of detail about how scripting uses key value coding, a fundamental mechanism and foundation that's being reused for a lot of things now in Cocoa. I'll talk about error handling because it's so important. I'll go into some detail about scriptability in apps that use Cocoa bindings. And I'll leave you with some debugging hints.

So today's sample app. If you're on the Cocoa Dev mailing list, you know that Scott Anguish and Malcolm Crawford have been doing a tremendous job of answering questions about Cocoa bindings. And Malcolm has actually gone through the trouble of creating a pretty nice little sample of how to hook up a custom view to bindings. So when I was casting about for what should I make scriptable, this seemed like a pretty obvious choice. Because one of the things I want to show you is how well bindings and scripting interact now.

The first thing you do when you add scriptability to an application is that you have to declare the scriptability so that applications like Script Editor that will drive the scripting can get the scripting dictionary, can show it to the user, can compile scripts and things like that. And in Tiger, we're adding a new mechanism to do that, a new file format actually called the SDEF file format.

So what is there to declare for an application scriptability? Well, as you can see in the screenshot, which is from Script Editor, there's scriptable classes and there's scriptable commands. This is the scripting dictionary for the graphics bindings that I'll be showing you. And it has a document class. It's very simple. It just has circles, the circles you saw on the screen there. And there is a circle class also with a variety of properties associated with it, like the position and the color and the radius of the circle and some shadow aspects.

So there are three main categories of things you declare in Scriptability. The classes that the scripter sees, the commands that the scripter, you know, the person who's writing the scripts can use, and then types that are used by class properties and command parameters. And we have a pretty big variety of types available now. It expanded a lot actually in Tiger, but just some of the more common ones you'll be using are enumerations and records, which are new, and support for some custom types too.

So the old way in Panther and earlier for declaring your application scriptability, it was done by providing a pair of files in your application, a script suite file and a script terminology file. The script suite file was full of implementation details and the script terminology file was full of human readable strings to show to the user. These always lived in your application's resources directory and they're kind of hard to work with mostly because they're split across two different files that you always had to keep in sync. It was a feature. It had something to do with internationalization. It's not really being used that much. And actually, there are other mechanisms in Cocoa for getting roughly the same thing. But when I say that it was hard to work with, don't let me talk you out of trying scriptability right now. They're not that hard to work with. You don't have to wait for Tiger to get a good head start on adding scriptability to your application. And also, some of the things we're doing while adding support for this new scripting declaration file format are kind of carrying over into the Script Street world. So, you know, warnings about things that you do wrong and stuff like that are also being applied to the old file formats just serendipitously.

So working with them is also getting easier while we're doing this. And, of course, if you add scriptability to your application now because it's such a valuable feature, you know, users want to do workflow, things like that. of course we won't break compatibility for your application in Tiger, even though we are doing some pretty big changes.

So that was the old way of doing it. I won't go into too much detail about that. I actually went into quite a bit of detail about it like two years ago. The new way, which I will discuss in detail, is SDEF files. The SDEF file format itself is not new. It was introduced way back in Mac OS 10.2 in the form of some documentation and a command line tool called SDP. That was pretty handy. you could start with an SDEF file, and it would parse that and output Carbon AETE resources, as well as Cocoa script suite and script terminology files. So even though Cocoa didn't have built-in support for this more convenient file format, more powerful file format, it was still useful for you to build your scriptability. And I think some applications at Apple, like Mail, for instance, actually they write all their scriptability support in SDEF, And then they use STP during a build phase to output the script suite and script terminology files that Cocoa needs at runtime.

But that won't be necessary anymore. What's new in Cocoa is that it parses these SDF files natively. They still in general will probably live in your application's resources directory, but Cocoa is not going to just load them automatically, every SDF in your resources directory like it did with ScriptSuite and ScriptTerminology files because that was pretty inconvenient in the past. ScriptSuite declarations would get loaded into every application whether they were applicable or not. and it wasn't exactly the perfect way to do things. So now what we're gonna let you do is you specifically specify in an entry in your application's info.plist what the top level scripting definition file is. In our example, it's gonna be graphics bindings.sdef. One thing that hasn't changed is that you still need an entry in your info.plist, NSAppleScriptEnabled equals yes, to turn on scripting in the first place.

So the SDEF file format is XML based. Nonetheless, it is easier to edit than the old script suite and script terminology formats were. A lot of that ease comes from the fact that it's just one file now. Programmatic information and human readable information are all in the same file. It lends itself well to attractive, informative scripting dictionaries. It was really designed to represent easily the things that users need to see to be able to write scripts easily. And if you want to get every last bit of detail about this file format, just go to terminal and type man sdef. There's a pretty large manual page that declares everything in big detail.

So the first category of things that you declare in SDEF files are class declarations. And you're declaring your application scripting classes, which very often have a very tight coupling with your implementation classes, you know, the ones that came about just as a result of your design, your object model. But not always. Sometimes there are places where you'll have classes that are just for scripting.

When you declare classes, you typically declare the scriptable properties of those classes. And something that's a little rarer, you declare the commands that instances of those classes can handle. And I say it's rare because the AppleScript standard suite includes a pretty complete set of fundamental operations. And customizing that is very often not necessary.

A scripting class declaration has a human readable name and description, a four character code that identifies it, and if you're hoping that I'd be saying there are no more four character codes for people who've worked with this in the past, I won't be. They're still there, but we know that people hate to work with them. So we may make some progress in that in the future.

So it also has implementation details like the name of the Objective-C or Java class, and property declarations, and just a terminology mismatch for historical reasons. we call properties in AppleScript are usually called attributes and to and relationships by Cocoa programmers and element class declarations in AppleScript are usually called too many relationships by Cocoa programmers.

So here's zooming in on the circle, well the document and the circle class of that graphics binding app. So you can see the document class has just one element class, circle. So the elements of one of these documents are circles. And there is a circle class with the properties I mentioned earlier.

Here's what you do to make that sort of thing appear in your scripting dictionary. This is part of the declaration, this is most of the declaration for the Circle class. It has a name and a human readable description and a four character code. When I talk about four character codes, by the way, I'll be pointing you later to some documentation, the new scripting interface guidelines that give advice about how to pick those.

implementation details like the Cocoa class. We have an Objective-C class in our project also called Circle. Whenever in an SDEF file you see a Cocoa element with an attribute like class after it, that's always an implementation detail. These SDEF files are made to be read by a number of different clients like Script Editor will be reading them as well as Cocoa reading them for its own purposes. So all the implementation details are kept separate that way.

Properties also have names and descriptions and four character codes, but they also have something else, they have a type. So in our simple example here, the types of the X position and the Y positions are real, you know, floats. And the type for the color is a color that's built into our system called color.

An implementation detail that you get to provide when you're declaring that a class has properties is the key for the property. And I'm going to be talking about key value coding, key value observing a lot today. These keys are the strings that identify the properties for use by these fundamental systems in Foundation.

Cocoa command declarations, which I won't go into in too much detail because declaring custom commands is hopefully very rare, look very similar in SDEF, same sort of shape. Cocoa already includes declarations of the commands in the standard suite, get, set, move, duplicate, open, print, close, quit, save, things like that. A new feature in SDEF, something that people have been asking for, is the ability to, in rare situations, replace our command declarations with customized ones that have more parameters, things like that. So you're going to be able to do that now with this new file format we've adopted. And you can, as always, add your own custom commands.

So a command declaration has a human readable name description, two four character codes instead of just one, and then an implementation detail like the name of the Objective-C or Java class that encapsulate instances of those commands that come over as a result of running the script. And commands have direct parameters and they also have other kinds of parameters. These are mentioned pretty much in the Apple script language guide, but we do let you declare them with great fidelity. So you're able to do things that match exactly what people who've read the Apple Script Language Guide would expect. And if a command has a return code, you get to declare the type of that too. Just a quick example, the send command from mails scriptability, declared as a nestf, is very simple. It has a name and description, a pair of four character codes, and this one has a direct parameter that represents the receiver of the command. In this case, the type of the receiver will be a message. is another class that's also declared in male scriptability.

So basic types that you get to use. The set is pretty clean. The names that you use in the SDEF are pretty much the human readable names that users see in scripting dictionaries when they're opening it up in script editor or something like that. So we provide the set that people are expecting, things like Boolean, color, date, file, integer, real, so on. Each of these maps to a Cocoa class so that your scriptability code will get an instance of the Cocoa class whenever one of those fundamental types appears in the script. So booleans map to NSNumbers, integers also map to NSNumbers, colors map to NS colors, and so on.

Another type that you'll see in SDEF is the specifier type. It corresponds to an AppleScript reference, what's called an AppleScript language guide of reference. And in Cocoa, the class that represents this is NSScriptObjectSpecifier. And a specifier identifies one or more scriptable objects, like words four through eight of text of, you know, a text-edit document or something like that.

And here's an example use of that, just the close command has a direct parameter that represents the receivers of the close command and the type is specifier, which means that you send a close command to a set of objects that are specified, like, for example, you know, documents one through three or something like that.

Another type that you'll see in S-DEF is a location specifier, which is a lot like a specifier, but not quite. It corresponds to an AppleScript language guide insertion point, and in Cocoa, the class that's used to represent this is NSPositionalSpecifier. And it identifies an object location, which will very often be the same as the location of an actual object. Sometimes it'll be the position before or after a specified object. And here's an example use. The standard suite's move command has a to parameter. It's very popular to name parameters with prepositions. So in this case, this very fundamental command, the to parameter, its type is location specifier. So you're specifying the location to which things should be moved.

Some more types that you get to use in SDEF, another one is enumerations. If you've been programming in C, this is very old news. It's the same concept in AppleScript. They're named values. Here's an example. It's the declaration for the printing error handling enumeration, which is used by the new enhanced print Apple event about which a tech note appeared on our web about a year ago. So when you send a print command to an application that supports everything properly, you get specify what kind of PostScript error handling gets done, detailed or standard, so, and that's specified just within enumeration. So scripters don't have to type in integers or things like that.

of ancient AppleScript concept is the list type, but Cocoa hasn't really supported it properly until now in Tiger. It will, you can preface just about any type name with list of, and that indicates that it should be one or more of those things. Your implementation in this case will always be passed in this example for list of file and NSArray of NSURLs. So even when the script specifies for example just one file, we want to make it very easy for your implementation code not to have to check multiple types, you know, is it a bare NSURL, is it an NSArray of URLs. If you declared list of file, you'll always get an NSArray of NSURLs.

A new feature in SDEF that we think will turn out to be pretty useful is complex types. And I don't mean it has a real and imaginary part. I mean that the types is one of a variety of different types, alternative types. So this will be useful in situations like specifying the address book label in address book scripting for a phone number or an email message. You can say home or work or something like that. You can just do this with a string if you want, but there's a little bit more checking that can go on at compile time if you support either a string for custom labels or one of an enumeration for predefined labels. And this not only lets scripters write what they want to write, it lets them know that they can write it because information about this actually appears in the scripting dictionary. So scripting dictionaries and SDEF are going to be much richer, filled with a lot more hints to scripters about what they can actually do, what's worth trying.

And here's a sample from the standard enhanced print Apple event. The type of the direct parameter, the receiver of this command, is list of file or specifier, which means you can either print a list of files or one file that is being picked with the standard file chooser dialogue or something like that, or a specifier, for example, a list of documents that are already open. You can print those too.

So something that SDEF has that the older mechanisms didn't have is a way to take real control over the reuse of Cocoa's standard declarations. As I mentioned, Cocoa doesn't automatically just read all its own files anymore. It makes you import them. So you'll have much better control. This is done with an import tag. And here's a sample of what it will look like. name equals foundation, standard commands.sdef. We'll be bundling up all of our standard command declarations in an SDEF, and you can import them if you want to save space in your own SDEF and also to take advantage of when we add new standard commands should that ever happen. Or if you're doing heavy customization, you can just copy and paste that all into your own SDEF and make sure that you have complete control over what goes on.

Import can specify more than just SDEF files that are in one of the frameworks that the application is linked against. It can specify SDEF files that are in other bundles, for instance, or even anywhere at all. There are forms of it that specify, for instance, even an absolute path. So this will be useful, for example, you are going to be given the opportunity to build your top level SDEF on the fly if, for example, you have an application that's heavily plugin and the scriptability is spread among many different plugins potentially, you're going to be able to do that pretty easily. The mechanism how this appears in Cocoa is a little undefined right now. There's probably going to be an application delegate or something like that. But the info P list declarations are already defined to support this dynamic SDef concept, and you'll definitely be able to do that.

Something else that Cocoa has been lacking, but we now have because we've adopted S stuff, is called the class extension tag. And if you've been working with Objective-C and you know all about categories, it's pretty much the same thing. So actually you can do a few other things that you wouldn't expect to be able to do with categories. So we're putting this here for one reason, it's gonna make putting scriptability in bundles easier.

So if you have a bundle or a plugin that adds properties to the top level application class, this is how you'll do it. You'll extend the application class. In the past, people have had to do strange things like subclassing the application class, even when there wasn't really much reason to do that, except we didn't provide a better way. So now we are providing a better way.

Other features, if you've been working with Cocoa Scripting and you've seen the scripting dictionaries that result where things are a little bit randomized, that's because the ScriptSuite format is property list based and what's more is using property list dictionaries, which of course have no inherent order. So things get moved around a little bit and you can't really control how things are presented to the user, the writer of the scripts. SDEF has no such problem.

A big feature of SDEF is that it's because it's going to be a file format that's shared outside of just Cocoa. There's actually API in the OSA framework for reading these. They're going to be recognized natively by Script Editor and presumably, hopefully, other scripting tools too. And the result of that is that when Script Editor or some similar application needs to get at the scripting dictionary so that it can compile a script or just show it to the user, they're not going to have to launch your application to do it. It just has to look in your info P list.

So yes, very old news in the Carbon world, and Cocoa is finally catching up in this regard. So yeah, there won't be any more application launching. Script Editor will just dig around in the info P list, and we'll be able to follow the imports and things like that. One caveat with that, by the way, is that if you're doing the dynamic SDEF feature, well, just as in, you know, old Carbon tradition, well, then your application will still have to be launched so that you can actually build it right then.

Other features, SDEF includes help for letting you provide backwards script compatibility. When you're rearranging your scripting, and it seems that nobody ever gets it right on the first try, you want to remove things, you want to rename things, but you don't want to break people's existing scripts gratuitously.

That's kind of rude. So SDEF has a couple features, like the hidden tag, which means if you have an element class or a command or something like that, that you're deprecating because it's not, you know, you don't want it around anymore, it's just cruft. You know, you can leave that in there so that existing scripts keep running, but new users who open up your scripting dictionary and look at it won't ever know that those ever existed. They're hidden. So, and the synonym tag fixes similar problems when you're renaming things or, you know, getting the four character codes just right or something like that.

One thing that's been a source of big confusion in Cocoa is how we handle the scripting of files. And with SDef, we're really going to be cleaning it up. There is a single type. It's a public type. It's called file. And it's public unlike the old NSString file path that some of you are using in your script suite files. This one is genuinely public. And, of course, you can use list of file. And when you do, your code will always get an NSArray of URLs. And scripters, through the magic of Apple event coercions, get to use files, aliases, HFS pass, POSIX pass, whatever they're most comfortable with, and your code will never be able to tell the difference. It always just gets URLs.

So implementing your application scriptability, you've declared it to the outside world and now you actually want to hook it up and make it work. And this requires you to know all about key value coding. And this isn't a change in Tiger. Cocoa scripting has always been built on top of key value coding. And what that means is you have to make your scriptable classes key value coding compliant. And just to do the same old terminology review, properties are attributes, and element classes are too many relationships.

What does key value coding do? Well, first of all, it's worth mentioning that it's the same mechanism that Cocoa bindings and now CoreData uses. It gives access to object properties using a very generic API that identifies them by key. And keys, in this case, are just strings. Like in today's example of the graphics bindings application, the circles of a graphics binding document or the color or the radius of one of those circles. So, the same keys that appear in SDEF files and are actually also used in IB's bindings inspector are used throughout this API.

So to be KVC compliant, the short, terse answer is you have to implement enough methods or whatever to make these two methods in NSObject work, value for key and set value for key. So the quick and easy way to do that is for each one of the keys, implement a method that has the exact same name as the key so that when Cocoa Scripting calls or invokes value for key, value for key is smart enough to root around in your class's method list and find that key method and invoke it. If the property is mutable, is read right, then you also implement a set key method. and these are just as simple looking as they sound. For our radius property where the KVC key is radius, there's a method named radius and there's a method named setRadius.

for each too many relationship, for each collection of pointers to other objects that your scriptable has, you have a choice of how you implement that. Typically you would, again, implement a method named key that would return an NSArray, a collection of the related objects. But sometimes for implementation reasons, complexities arise and you don't have the pointers to the other objects stored in an NSArray. If that's the case, then instead of implementing key, just implement count of key and object in key at index. And again, key is replaced by the actual key that we're talking about. And key value coding is smart enough that it'll find those methods and use them when it needs to. So how do you decide between the two of them? Just whichever is easiest to implement is the general rule. If you change your mind later, perhaps as a result of measuring and doing performance analysis, it really makes no difference. There's nothing outside of key value coding that's really going to see this, unless of course you declare these methods in a header and show them to other programmers on your project.

for each mutable to-many relationship where objects can be inserted or removed via scripting, via Cocoa bindings, via core data. You would also implement insert and remove methods whose names follow the patterns you see here. So a quick sample, the graphics binding applications document class has a circles relationship. All the accessors that key value coding needs are right here. So circles returns an IVAR, insert object in circles at index, remove object from circles at index, just invoke the regular NSMutable array methods.

So that was just the tip of the iceberg as far as what key value coding lets you do. You know, writing, having you write accessor methods is the simple way to introduce it and is what people are most comfortable with right off the bat. Key value coding has a couple other different ways to grub in your objects. It even has direct IVAR access. So you don't even have to write any accessor methods at all. You just have to give your IVAR the same name as the key. And key value coding's value for key and set value for key methods will poke at it directly. This is kind of nice because, of course, it's less code.

And it's also kind of nice because if you do have to add code, you actually have to do something when somebody sets the value. You have to make something else consistent or something like that. You can add the set accessor method, and key value coding will simply start using it. It'll stop groping at the IVAR directly and use your set accessor method. So we have different layers of functionality for you to use depending on how much customization you need to do, how much code you're willing to write. It goes all the way from virtually no code to not that much code. So see the documentation where this is all now described in great detail. For even greater detail, see the Tergit pros and the NSKeyValueCoding.h header file which explains the default implementations of methods like value for key and set value for key in just excruciating detail.

So great error handling is worth singling out because it's something that Cocoa Scripting hasn't done so well in the past, and it is tremendously important. Error handling is important because it helps scripters learn the language. You know, they learn by doing. That's a scripting language. They learn by experimenting, making mistakes. They need feedback about what their mistake was. So, and as a nice side benefit, when you're testing your scriptability, good error handling, you know, helps you debug, too. We've made big improvements to our error handling. If you've ever scripted a Cocoa app and gotten it wrong or worked with things like Apple Script Studio and gotten it wrong, you've seen these incredibly unfriendly error messages, like NS cannot create command script error. Entire messages like those will be just completely disappearing. We're just gonna do. We're just going to be doing the normal Apple event error messages that we should have been doing all along. So let me show you what I mean.

So this is the graphics binding project that I was just telling you about. Let me just point you at the S stuff real quick. Now here are some import directives. In the shipping version of Tiger, these will actually be a little more complicated 'cause it'll actually point to things in Cocoa. But right now I just copied these standard SDefs into the project to demonstrate it here. So some imports of the standard types and item and commands and classes that are built into Cocoa. Here's that circle class I was telling you about, very simple. Implementation details are tagged with the Cocoa element. And this is interesting. down here you see these have no Cocoa Key and it's because there's a default value for those. In this case it's just color or radius or shadow angle. So it tries to save you a little bit of typing but if you wanna be explicit that's okay too.

So the class, the actual source code, is pretty simple. Here is the accessors for the radius methods. And really, these aren't even actually necessary either. But if you get, things get a little complicated and you do have to start writing accessor methods, this is what they'll look like.

And let's launch Graphics Binance so I can show it to you. It's pretty neat. It's like super dot view or something like that. So you can do things like select different dots. And this is all done with Cocoa bindings with very little code. There's a good bit of code in the actual view, the graphics view that you're seeing here, but that's meant to be highly reusable. The rest of it is nearly nothing.

So you can move things around. You can select a bunch of them. There's this neat little joystick control for moving the shadows around. Of course, the controls take effect on the entire selection at the time. So to script that a little bit, there we are. Let's open an even simpler document.

That does not actually work quite yet. And plus this is already compiled anyway. But it's standard Apple script. You get to do things like setting the radius. Apple event coercions and things like that work. So you get to set the radius to an actual text string. And if you set it to something that's complete nonsense, finally it actually says so. Hopefully you can all read that. It says, "Cannot make gobbledygook into type real," which is what it should have said all along.

and we'll be doing more than just type errors, checking for indexes and things like that. Graphics binding cannot get an error, can't get document seven, invalid index, 'cause there's only one of them open. That's it. It's not supposed to be anything earth shattering. So it just works now.

So the kind of things that Cocoa is going to be able to check for you are when the scripter uses the wrong types, nonsense object specifiers, you know, document four of word eight might not really be what they intended to type. We're going to catch stuff like that. Things like out of range index specifiers. We're going to be able to catch pretty much everything except invalid property values pretty much. So when you want to clamp the values of numbers or something like that, Cocoa can't catch that for you. Everything else it will. What you're going to be doing, and this is not implemented in the seed right here, is use the standard key value coding compliant, or the standard key value coding mechanism. There's a method on NSObject called validate value for key error. And what you'll be doing is just implementing a method whose name is validate key error to return an error. So validate radius colon error colon. And what's really great about this is it's tremendous code reuse because it's the exact same mechanism that Cocoa Bindings uses.

In more complicated situations, if you end up implementing your own custom commands, you should know about these methods. I think these are all added in Panther actually. And a script command, current command, they weren't all added, current command was added, will get you the script command that's being executed right now. So if your accessor method is being called and you want to set an error number in it or something like that, this is how you find out, number one, whether or not your code being called because of scripting, it's all meant to be highly reusable. It might be being called because of Cocoa bindings or core data. But if it's being called because of scripting, there will be a current command. And one of the things you can do if something goes wrong is to send that current command, set script error number. Now you shouldn't just, you know, pick a number out of the ether before you, you know, or you may end up have to, having to. But before you do that, have a look at the Apple script language guide where a bunch of error codes that people who write scripts are expecting to see are documented. And they're all declared as constants in CarbonCore MacTypes.h, which you typically import with the umbrella header, so core services, core services.h. There's another method on NSScriptCommand called setScriptErrorString. Don't use this gratuitously like we were. That's how we ended up with things like NS cannot create command script error. If you're using one of the numbers that AppleScript recognizes, and it recognizes a bunch, don't set any error string, just set the number and AppleScript will pick the right string for you.

And when talking about error handling, it is worth focusing on the specific brand of error handling, type checking. Because in addition to all the other things where you want to help scripters experiment, there's a big reliability issue here that you might not have realized while implementing your own scriptability if you've been doing so. Is that it's possible for scripters to crash your app by arranging for objects of just the wrong type to be passed to your code. So, we're going to be closing that up because SDef has very good support for declaring exactly the types that your implementation can handle. Cocoa is going to make sure that your implementation is only passed objects of the exact right type to. And as a result of the good type declaration, the user is going to get good hints about what their scripts can do.

So sometimes in programming systems, when there's a lot of type checking, that can impinge flexibility. But in this case, we don't think it will. We think there'll be more flexibility now because Apple Events, upon which all this scripting stuff is built, has always had a pretty good Apple Event coercion scheme for coercing things of one type to another. And when Cocoa has good type information, it uses that properly. So the user will be able to, you know, do things that are close enough, typing in text, in -- you know, typing in a number in textual form instead of actually getting the number right.

Scriptability and Cocoa Bindings. Cocoa Bindings, as hopefully you all know by now, is a big new technology that was introduced last year at WWDC for creating user interfaces with not a lot of glue code. We are making improvements to how nicely scriptability interacts with that. So both scriptability and Cocoa Bindings, and now Core Data too, use key value coding very heavily. So when you make your classes key value coding compliant, you're killing two or three birds with one stone.

We also introduced last year something that goes on top of key value coding called key value observing. Now, Scriptability is not interested in key value observing. There's no way to write a script that, you know, observes objects in another application. That would be very interesting. It just depends on key value coding. But those same classes are very often implemented or are very often reused between Scriptability and bindings. So for bindings, you have to be key value observing compliant. And we've made some improvements to how scripting uses KVC to make that easier for you.

So Cocoa Scripting now uses setValueForKey, which is a new method that was introduced last year. This makes it easier for you to use the automatic KVO notification feature. The old takeValueForKey method, which Scripting was using, is now deprecated. If you have existing code and you're overriding it for some reason, we'll still invoke it in that case 'cause we don't wanna break your application, but we encourage you to move to the newer method because it works properly with KVO.

Something else that was added to key value coding as part of the Cocoa Bindings feature is a new method called mutable array value for key. When I was talking about those insert and remove methods that you have to implement on your too many relationships, this is the method that has the smarts to go find those. And again, it takes advantage of this automatic KVO notification feature where key value observers are notified merely because a set accessor or an insertion method or a move method is invoked. And, just as in the simpler case, old methods like insert value index and property with key will continue to be invoked in Tiger for the foreseeable future for backwards compatibility reasons.

So automatic KVO means, because you have to be key value coding compliant anyway for all your properties that you're making scriptable, means that you're probably already KVO compliant for those same properties. So you can do things like binding to them from the user interface. So for example, how this works, when you're scripting object, it sends set value for key because the user, the scripter, ran a script like set radius of circle one, a front document, something like that. Set value for key will call and find your set key method, but then it also goes ahead and does, and notifies observers like bound UI objects of that change too. So the UI will update automatically without you having to write anything into your accessors.

For too many relationships, mutable array value for key is used by Cocoa Scripting now. How that works is Cocoa Scripting calls mutable array value for key, and what's returned is actually a collection proxy that represents the relationship that your class has to those other objects, like an NS Graphics Bindings document's relationship to circles. So it's returned looks just like an NS Mutable Array to the client, Cocoa Scripting itself in this case. And as NSMutableArray API is used to insert and remove or replace objects, the container objects, insert object and key index and remove methods are invoked automatically. So the client of key value coding has a tremendous amount of flexibility about what they can do. Anything that an NSMutableArray can do, including things added in categories. the owner of that relationship only has to implement a pair of methods. And as all this happens, bound UI objects get updated automatically.

I've been talking about automatic KVO notification, so I guess I should mention manual KVO notification, just so you know why we bother to call it automatic at all, because there's another system, too. And they coexist very well. You can have automatic KVO notification turned on for class, and then also use manual KVO notification for more complicated situations.

Shouldn't be needed that often for scriptable properties, But you can use it, for example, when your class is changing its own IVARs directly outside of a KVC compliance method like set key. And it's pretty easy to use. You just do a will change value for key before the change, and a did change value for key after the change. Thank you.

So I'd like to leave you with some hints about debugging your application's scriptability. There's a lot of logging available that Cocoa Scripting will do to help you figure out what's going wrong. And also, every time we touch this stuff, we seem to add or clean up a description method in any of the Cocoa Scripting classes.

So logging, Cocoa, as we wrote in the support for SDef, we made sure that all the errors and warnings that it spits out are useful. So I'll demonstrate that in a little bit. So mistakes that you make are easy to pin down instead of things just going mysteriously wrong. And we also added this support for warnings and errors, improvements serendipitously to the old file formats too, ScriptSuite and ScriptTerminology. So when you see these, fix the warnings. They all actually mean something. And if it's not descriptive enough, send an email to one of the public lists or to Cocoa Feedback or something like that. You can have Cocoa log information about every scriptable command as it happens, just with the simple default. Default's right, NSGlobalDomain, NSScripting, debug log, level one. And if you only want to turn on logging for one application, substitute NSGlobalDomain with the bundle identifier for that application.

I mentioned that we added a bunch of description methods to classes. One of them is NSScriptSuiteRegistry and then all the classes like NSClassDescription, NSScriptCommandDescription, things like that. So if you want to see what Cocoa pulled out of your SDef file or your old ScriptSuite file, just break the application anywhere and type what you see here, Po, NSClass from string and the ScriptSuiteRegistry, shared ScriptSuiteRegistry. and they'll send a description message to the ScriptSuite registry, and just an enormous amount of information will be presented to you, so you can see exactly what Cocoa thinks you said about your application scriptability.

There are some other description methods too. And a script command has one. I don't know if everybody's found it yet. If you're in the middle of one of your scriptability accessors and you're wondering why was this called, you're watching script editor send events but it's still not obvious, then you can print a description of the current command. And if you are an old Apple Events hand and you want to see what Apple event resulted in the creation of that NS script command, you can get the Apple event from the current command and print its description too. So demo. So let's very quickly just do something stupid in our SDEF file.

And I just fat fingered one of the type names here. And cause the dictionary to be loaded. And it now gives you a super informative message that will help people debug. SDF warning for attribute display name of class document in suite graphics binding suite. Strang is not a valid type name. So we're trying to help make it easier to debug this stuff. So I won't leave that broken. and just relaunch graphics binding again. And let's look at all the information that's available to help you debug this stuff.

A tremendous amount of stuff. And this is important, because people had a good bit of difficulty in diagnosing their mistakes. So now we're going to make it easy for you to see exactly what's going on. So in this circle class, there's pretty much every information that can be-- everything that's worth knowing is here. And while I'm here, let me show you another debugging trick that I think you'll like. Let me put a breakpoint on one of our simple accessor methods. So just set radius and continue that.

cause it to be called with a simple script. So setRadius. So let me show you what Cocoa Scripting is doing right here, by the way. If you follow the stack trace, You know, the Apple event manager is getting the Apple event, this is Coco's Apple event manager, making a script command out of it, executing the script command, and this is the set command. It eventually boils down to a call to the key value coding set value for key method.

which is smart enough to call your setRadius method. Now, this one is interesting. If you take a peek at one of these private function names, NSSetFloatValueAndNotify, what does and notify mean? Well, it means that there are key value observers registered with this object as a result of the bindings that are in the UI of this program, and it's going to tell them that the value changed, even though this method does almost nothing. Thank you. So let me put a good break point at the method that does that.

The way automatic KVO works, by the way, is it causes invocations of will change value for key and did change value for key around the invocation of your set method. So let's put a breakpoint around on did change value for key and continue. Xcode wants my attention, but I don't want to talk to it. So set float value and notify. It just finished calling your set accessor. Now it's calling did change value for key. So it's going to send did change value for key is where notifications are sent out to any observers. So if you've been working with Cocoa Bindings, by the way, you might have had some trouble figuring out who's observing who. Let me show you this little trick right now. PO self-observation info. Observation info is declared as a void start, it's an opaque type. I don't want you digging around in there too much. I don't want you to write dependencies on the internal structure of that, but it's okay to take a peek. Here's what it outputs.

This object is one of the circles in graphics binding, and there's observers of its shadow offset property, color radius, shadow angle, X lock, Y lock. It's because the graphics view is observing all this stuff so that it knows whether or not to redraw the circle. So, great deal of information there for you. So, that's it for demos. So.

So one thing we've learned over the past year since releasing the Cocoa Bindings functionality is that we achieved our goals of helping you to write not much code, but I think we ramped up the learning curve a little bit for Cocoa. And a big part of that is debuggability. And if you were at the Cocoa Binding session a couple of days ago, we pointed you to a new default that we're adding for binding to give you more logging of what goes on in bindings. We're going to be doing more stuff like that. We want to make it as easy as possible for you to find your mistakes while you're learning to use this stuff quickly. You'll see more description stuff, more logging, special defaults that you can turn on to do sorts of trickery, things like that.

So before I go, I want you to point you to this very important document, make sure absolutely everybody has read it, the scripting interface guidelines, which are pretty new, but they're not that new. I think they're about four months old now. They're since last WWDC, though. And I want you to read this because consistency across apps is tremendously important in scriptability, just like as it is in regular graphical user interfaces. People want to learn stuff once and reapply it over and over again. Following the guidelines helps them do that. It makes your scriptable application look better. It makes other scriptable applications look better too when everybody's looking the same.

So Cocoa itself, of course, either follows these rules scrupulously right now or is about to start following these rules scrupulously, or we might just change some of the rules a little bit. But in general, what Cocoa does is going to be perfectly consistent with what we suggest you do. And we're making it easy for you to follow these guidelines yourself. And now that you know about this, read this. If you're about to start work on a new application and you haven't read this yet, read it now. Because it actually has some design advice about how you can save yourself a little bit of work later and things like that. So it's at developer.apple.com/technotes. It's number 2106. So for more information, you can go to our website and just click, click, click away. Or you can send an email to Matt Formica.