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 has known transcription errors. We are working on an improved version.

Good afternoon. My name is Mark Piccirelli. 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 as a 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's 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 script, 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 system. The new scripting declaration file format are kind of carrying over into the script suite 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. You know, of course, we won't break compatibility for your application in Tiger, even though we are doing some pretty big work. So, you know, we're working with them. So, you know, we're working with them. 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 Terms.

Mark Piccirelli 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. I think some applications at Apple, like Mail, for instance, actually write all their scriptability support in SDEF, and then they use SDP 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 SDef 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 SDef in your resources directory like it did with ScriptSuite and Script Terminology 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 going to 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 going to be graphics bindings.sdef. One thing that hasn't changed is that you still need an entry in your Info.plist NSAppleScript enabled equals yes to turn on scripting in the first place.

So the SDF file format is XML-based. Nonetheless, it is easier to edit than the old script-sweetened 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. 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. What we call properties in AppleScript are usually called attributes in 200 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 of 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 reals, 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 and 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 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. The receiver will be a message. Message is another class that's also declared in mails 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 S-DEF is the specifier type. It corresponds to an AppleScript reference, what's called an AppleScript language guide or 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 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 SDEF 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. Here's an example use. The standard suites move command has a to parameter. It's very popular to name parameters with prepositions. In this case, this very fundamental command, the to parameter, its type is location specifier. 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 Apple Script. 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.

Mark Piccirelli So when you send a print command to an application that supports everything properly, you get to specify what kind of post-script error handling gets done, detailed or standard. And that's specified just with an 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, an 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 dictionary is an SDEF. Mark Piccirelli A lot of the things that we're going to be talking about in 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 dialog 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.

Mark Piccirelli This is done with an import tag, and here's a sample of what it'll look like. Import name equals foundation standard commands dot 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. Mark Piccirelli 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. Thank you.

[Transcript missing]

Something else that Cocoa has been lacking, but we now have because we've adopted SSTEP, 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.

Mark Piccirelli So we're putting this here for one reason. It's going to make putting scriptability in bundles easier. So if you have a bundle or a plug-in 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 script suite 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. Mark Piccirelli A big feature of SDEF is that 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, other scripting tools too.

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, you know, we'll be able to, you know, 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. 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 ScriptSuite 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, you know, through the magic of Apple event coercions, get to use files, aliases, HFS paths, POSIX paths, 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 Core Data 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-write, 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 a pointer, 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, 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, you know, 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 grubbing at the IVAR directly and use your set accessor method. So we have different lines. 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. You know, 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 turgid pros in the nskeyvaluecoding.h header file, which explains the default implementations of methods like value, set 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. They learn by doing. It's a scripting language. They learn by experimenting, making mistakes. They need feedback about what their mistake was. And as a nice side benefit, when you're testing your scriptability, good error handling 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." And tiger messages like those will be just completely disappearing. We're just going to 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. Here are some import directives. In the shipping version of Tiger, these will actually be a little more complicated because it will 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 items 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 want to be explicit, that's okay, too. So, let's go ahead and start.

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.

Let's launch Graphics Binance. I can show it to you. Here it is. - 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, let's open an even simpler document.

does not actually work quite yet. So, and plus this is already compiled anyway. So, But as standard Apple script, you know, 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 I will be doing more than just type errors, checking for indexes and things like that. Graphics binding cannot get an error, can't get document 7, invalid index, because 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 script 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. So and what's really great about this is it's tremendous code reuse because the exact 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. NSScriptCommand, CurrentCommand, they weren't all added. CurrentCommand was added. We'll 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 is 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 scripting, and then call it.

Script error number. Now, you shouldn't just pick a number out of the ether before you, or you may end up having to. But before you do that, have a look at the AppleScript 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 Coreservices.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 NSCannotCreateCommandScriptError. 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 you. 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. Mark Piccirelli And when Cocoa has good type information, it uses that properly. So the user will be able to do things that are close enough, typing in text, 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 observes objects in another application, though 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 because we don't want to 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.

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 remove 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. Mark Piccirelli So for example, how this works, when you're scripting the object, it sends setValueForKey because the scripter ran a script like setRadius of circle1 of frontDocument, something like that. So setValueForKey will call and find your setKey method, but then it also goes ahead 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 NS mutable array API is used to insert and remove or replace objects, the container objects, insert object in key to 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 NS mutable array can do. Including things added in categories. But 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.

Mark Piccirelli 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 setKey. 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.

So I'd like to leave you with some hints about debugging your application 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. Script Suite and Script Terminology. So when you see these, fix the warnings. They all actually mean something. And if it's not descriptive enough, you know, send an email to one of the public lists or to, you know, Cocoa Feedback or something like that.

You can have Cocoa log information about every scriptable command as it happens, just with a simple default. Defaults write, NS Global Domain NS Scripting Debug Log Level 1. And if you only want to turn on logging for one application, substitute NS Global Domain 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, NSScriptSuiteRegistry, shared ScriptSuiteRegistry. And it'll send a description message to the ScriptSuiteRegistry, 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. So, and if you are an old Apple Events hand, and you wanna 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.

[Transcript missing]

And I just, you know, fat-fingered one of the type names here. And caused the dictionary to be loaded, and it now gives you a super informative message that'll 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. Mark Piccirelli 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.

[Transcript missing]

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. will be presenting his presentation.

[Mark Piccirelli]

Thank you, Mark. So let me show you what Cocoa Scripting is doing right here, by the way. If you follow the stack trace, The Apple Event Manager is getting the Apple Event, this is Cocoa'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.

is the director of the NMSS program, which is smart enough to call your set radius method. Now this one is interesting. If you look at this, if you take a peek at one of these private function names, NS set float value and notify, 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 that does almost nothing. 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 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. So 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 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 debug ability. 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. So 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. Mark Piccirelli 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. Mark Piccirelli So Cocoa itself, of course, either follows these rules scrupulously right now or is about to follow them.

Mark Piccirelli So Cocoa itself, of course, either follows these rules scrupulously right now or is about to follow them. It's not that we're 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. Mark Piccirelli 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.

Mark Piccirelli 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. 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.