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: wwdc2000-128
$eventId
ID of event: wwdc2000
$eventContentId
ID of session without event part: 128
$eventShortId
Shortened ID of event: wwdc00
$year
Year of session: 2000
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC00 • Session 128

Cocoa in Depth

Mac OS • 1:06:34

This session provides an in-depth discussion of Cocoa topics, such as text, document classes, scripting, localization, Java, and Carbon interaction.

Speakers: Ali Ozer, Mike Ferris

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

The purpose of this session is to build upon the Cocoa Overview session, which you might have attended on Tuesday, to give you somewhat more detail into some of the topics that Becky touched upon that day, and also to give you a flavor more about how Cocoa works and how it's designed. So the in-depth discussions, the topics that we're going to provide you are the document objects, scripting, and undo, which are three topics that go in hand. The text system, we're going to give you a little detail on that.

Then we're going to give you a bit of performance tips and tools and how it impacts Cocoa in the context of Mac OS X. We're going to talk a few minutes about using Carbon from Cocoa, and also how to use Java to program Cocoa. Okay, so for the first part of the talk, "Document Scripting and Undo," I would like to invite Mike Ferris, who is a member of the engineering staff, on stage. Mike.

So I'm going to talk about three topics here, which all have a bit in common. Am I holding this wrong? So the document architecture and the AppleScript support and the undo support in the app kit all have some stuff in common. Of the features in the kit, a lot of the stuff in the kit is basically widgets and things that you use in your application but don't necessarily affect the design of your application.

Traditionally with the kit in the past, you've basically been able to structure your app however you feel you want to do that, and it hasn't really impacted you in your ability to use the kit. But as we try to add some of these higher level features, we find that the application If your app has a particular structure, it's a lot easier for us to do a lot more for you. The structure that we've kind of chosen to hang all this off of is the Model-View-Controller design pattern.

And I want to mention that basically all these features are separate, but they work really well together, and sort of with the document stuff at the center of the equation. So if you're not familiar with the model view controller pattern, I want to spend just a moment talking about that. This is basically a design pattern. It came from, I think, Smalltalk originally. And it's a way of structuring user interface applications and basically splitting up your object model.

Now, it divides models into sort of three categories, or objects into three categories. There's your model objects that are basically data-bearing. They have behavior, but that behavior is basically concerned with how your model, the thing that you're trying to represent in your application, works. And so you have behaviors here that help ensure the consistency and the invariance that you need in your model. The views... are basically the things that you use to present data.

Most of the objects in the kit are basically view type objects. They help you to present your data to the user. And then finally the controllers kind of sit in the middle, coordinate everything. Controllers are a large amount of the code that you end up writing in an application.

So here's a little picture. We can look at this two ways. There's a couple of dotted lines which you actually can't see very clearly here. Actually, they don't even look dotted anymore. The little, the black lines that kind of go down the middle of the box and divide everything into three spaces, on the far left we have the model area in the middle where it says NS Document and then it's Window Controller.

That's the controller layer. And then on the far right, you've got the view layer. Now the two boxes that sort of span and enclose different parts of this, these represent a couple of objects that are key in the document system and show where they kind of fit into this model. In the document system, NS Document objects tend to be the controller objects that own your model. And NS Window Controller objects are the controller objects that own your UI. So that's just a little brief introduction to Model-View-Controller.

So let's dive right into the document architecture. Basically, the intent here is to provide a structure where we can provide a lot of the common behavior that all document applications need and provide you with a place to put your behavior and easily customize for the kinds of documents that your application deals with. Now, the classes in the kit have a lot of sort of built-in implementation to do things like running the open and save panel, loading nib files, and managing the objects that come out of them, and all the sorts of things that you always have to do.

And they also provide subclassing and overriding points where you get to plug in your specific stuff. Now, the document architecture is also heavily tied into the application packaging, and in particular, the same data that the finder uses to know what kind of documents your application opens, the document system uses so that your application will know what kind of documents your application opens.

There's three main classes involved in the document system. The first and most obvious one is the NSDocument class. Basically, each instance of this class represents an open document in your app. It's responsible for loading and saving the document. It also is responsible primarily for owning the actual contents of the document, the model objects. You pretty much always subclass NSDocument to provide your specific kind of document, a text document, an image document, whatever it is that your app is going to do.

And just to sort of look forward a little bit to the other two topics in this part of the session, documents are typically the primary entry point for scripting in an application. And then also, each document usually has an undo manager. So we'll get into those two aspects a little bit later. Now, the next object is basically a singleton. There's one NSDocumentController in your application. It knows about all the open documents. And it also handles behaviors which are not associated with a particular document, like new and open.

This is also where you would go if you actually needed to query the metadata about your document types that's in your Info.plist. It parses all that when the application launches and provides you with some queries that you can make. Now, you rarely have to subclass this object. You can, it's easy, but mostly you don't need to bother. The majority of the kinds of things that you're going to want to customize, you can actually customize through the application's delegate object.

And then finally, there's Ennis Window Controller. Basically, this is a class which manages a window that is typically loaded out of an IB file, and it usually manages a window on behalf of a document. Now, documents can have multiple window controllers. So you might have a CAD application that had four windows, you know, that was showing a top and a left and a front view and, you know, maybe a preview wireframe of the 3D or whatever. You might also have an application that allowed multiple views of the same document to be open so that you could look at different scales or whatever. So documents can have multiple window controllers.

and although you don't have to subclass NSWindowController, it's very common to do so. And one last point I'd like to make about the WindowControllers is you can actually use them without NSDocument. You can subclass NSWindowController to provide controller objects for your auxiliary panels and everything else, and they provide management of the nib file contents.

So if you were at Becky's talk a couple days ago, you saw this picture. This is a non-document-based Cocoa application. And you may be wondering what the document system sort of changes this picture into. Basically, the delegate objects, the window delegate objects, become NSWindowControllers. Now, a window controller often is the delegate of its window.

It doesn't have to be. But if you're going to subclass it, it may as well be. And then there are NSDocument objects, right? And you can see that one of these document objects has a couple of window controllers. And other than that, everything's about the same. You can see also the NSDocumentController object that knows about all the open documents.

So that's a very brief introduction to documents. Now, an equally brief introduction to scripting. Scripting is based on key value coding. We'll talk about that in just a moment. And the two main areas of the scripting support is classes that support you defining your script terminologies, and then classes that support you handling script commands.

First of all, let's talk a little bit about key value coding, because this is a totally crucial concept in the scripting framework. We get key value coding from the Enterprise Objects framework. and it is basically a standardized way of accessing pieces of an object. What you do in your object is implement accessor methods, and they basically have a naming pattern.

You just, you know, you have a get method that's just the name of the key, and then a set method that goes along with it. Keys, for example, are things like the line width of this circle and the line color and so forth. And so some of the methods might be, you know, line width and set line width. width and set width, height and set height, whatever.

The standardization part of this comes in in that there are two methods, valueForKey and takeValueForKey. So valueForKey, you just give it the name of a key, like line width. It figures out, oh, look, okay, this object has a line width method. I'm going to go off and call this and return this, the value of that. And then takeValueForKey similarly works for setting.

But this allows a subsystem that knows nothing about your specific objects to nonetheless be able to, you know, get at the individual pieces of your object and deal with them. And so the scripting system makes heavy use of this. How? Well, We use key value coding to provide automatic evaluation of object specifiers.

If you're familiar with Apple script, you know that Basically, the receiver of an AppleScript command is usually an object that's qualified along the lines of, OK, well, tell the first graphic of the front document of the application sketch to do something. The first graphic of the front document of application sketch, that's an object specifier.

We pretty much provide automatic resolution of these things using key value coding. So if your document object has a key, which is the graphics that that document contains, and your application has a key, which is the documents that the application has open, then we can automatically find the first graphic of the front document.

In addition to the simple ones, we can automatically do, say, arbitrarily complex "whose" clauses in this way. We also use key value coding to provide default implementations for a lot of the common script commands. You can see that set and get, those are pretty easy to do with key value coding.

We can also do stuff like move and create and count and exists. So a lot of the core scripting suite commands actually have default implementations and your objects won't have to specifically support them at all. All they need to do is claim that they can support them and they'll automatically support them.

So let's talk a little bit about terminologies. In AppleScript, your scripting terminology is usually broken up into suites. And so this is the granularity that we have for defining these things. Script Suites are defined in frameworks or applications or loadable bundles. They are property lists that live inside of your frameworks or applications or bundles.

And at runtime, Cocoa is going to go out and find them all, all of the frameworks you're linked against, all of the bundles you've loaded, your app itself. We'll find all the script suites and then combine them all together, and that produces the terminology for your application. Now, the contents of a script suite is basically descriptions of the classes that this suite defines and descriptions of the commands that it defines.

The classes are represented by NS Scripting class description objects. And basically, classes have keys, both properties, or if you're used to databases, sometimes those are called attributes, and elements, sometimes called relationships. And then also a list of the commands that the classes support. Classes can inherit from each other, just like in an object-oriented programming language. And then the script command, the scripting command description class is used to define commands in the script suite.

And commands basically have arguments and they have return values and the things you'd probably expect. There's a property list definition for all of this stuff, so that you just sort of describe in a property list the various classes and commands. And then at runtime, those will all be parsed in, and these instances of these objects will be created to represent them.

Now, once the script editors say, knows your terminology, Somebody might write a script and then tell it to run, and at that point, you're gonna start getting script commands in your application. So script commands come in as Apple events, just like they do for any application in Mac OS X.

But we take them before you ever see them and turn them into NS script command objects. So these basically, NScript command objects are the things that you'll see if you have to implement a handler for a custom command, or if maybe your object knows that it can do counting better than the default implementation of the count command.

Basically, the script command allows you access to all the important pieces, you know, of that command. So it'll let you get at the receivers of the command, which is basically an object specifier. It'll let you actually get at the real receivers, which is the result of evaluating that object specifier. And subclasses of NSScriptCommand are actually where the default implementations are provided in cases where we can have a default implementation.

So you'll see in the framework, you know, NS set commands and get commands and NS count commands and so on and so forth. When you define your own commands, you can choose to have a subclass or not based on whether you're going to have a default implementation and possibly based on other things as well.

And then the other object that we have here is the NSObjectReference class. This basically represents one chunk of an object specifier. So again, graphic one of the front document of application sketch would turn into three object references that are all chained together. and again, object references know how to evaluate themselves using key value coding. Object references are found as both the receivers of a script command and also possibly as arguments to that command.

So this is all, you know, sounds pretty complicated. It's actually pretty easy to get started with this. We provide a lot of the behavior for you. We have a lot of the core suite and text suite implemented in the frameworks that come with Cocoa. So the application AppleScript class is implemented by NSApplication. The document AppleScript class is implemented by NSDocument. You know, the window class is implemented by NSWindow, etc., etc. You can see where that's going. The text suite is pretty much fully implemented by the NSTextStorage class.

So what that means to you is if you wanted to expose in your object model, Something that conforms to the text suite. You just have an NSTextStorage object. And so, for instance, in Sketch, right, Sketch has a text graphic type. And you can, you know, type some text in, whatever, right. And the text graphic type exposes one of its instance variables, which is an NSTextStorage, to AppleScript. And then, boom, automatically, the text graphic in Sketch will support the text suite.

So there's a lot of this stuff built in there. You can incrementally start exposing your own stuff. You have to do a little bit of work to start exposing some of your model objects. But often, with just a very small amount of work, you can get a lot of basic scripting functionality almost for free.

Finally, even briefer than the documents and the scripting stuff, I'll talk a little bit about Undo. So, First, let me make the point, undo should be implemented in your model. You don't want to implement undo in your interface layer, because then if something else comes along, like for instance, Apple script, and starts talking directly to your model layer, That's not a good thing if you're going to support multiple undo levels.

If somebody changes the font through the user interface, and then a script comes along and deletes that whole paragraph, and then later the user says undo, well, okay, what are you going to undo at that point? You've kind of lost the synchronization of the undo stack in the model. So it's very important that undo be implemented in your model. It's also the easiest place to put it. So that works out.

Again, for multiple undo, every change to your document has to be undoable, because if not, you're going to start getting out of sync again. Now, the class in the kit, actually in Foundation, that supports Undo is called NSUndoManager, and it basically represents a stack of Undo operations. As I said before, a document object typically owns an UndoManager, so in document-based apps, Undo stacks are per document.

If you're not a document-based app, then by default, Undo stacks are per window. Now, NSUndo Manager is based on another foundation class called NSInvocation. And what that means is that basically to implement Undo, all you have to do is do exactly the opposite of what you're gonna do every time you're gonna do something. Clear enough? So the code in yellow here is all you have to do in order to make setStrokeColor in Sketch undoable.

Now this is one of the primitive model methods in Sketch, right? The graphic object has this method. This is the way that the stroke color changes no matter who's changing it. And therefore, this is the appropriate place to put this undo logic. We know that the stroke color's never going to change unless it goes through this code.

And every time it does change, the first thing we're going to do is tell the undo manager to prepare a new invocation, which will basically, if undo is chosen, end up sending the same graphic object another setStrokeColor message with the old stroke color, that underbar stroke color, that's our instance variable that, you know, contains the stroke color. So as long as we just say, oh, OK, if I need to undo this, just call it again with the old value. and Everything is going to be set up and it's going to work just fine.

Now, a lot of these undo invocations, because they're implemented in the primitives in the model, might happen during an event, but NSUndoManager, by default, will group all of the invocations that get told to it during a single run of the event loop into one thing, and they'll all undo together. Let me give you a little bit of a demo. Mostly this will be a scripting demo. And if we could switch--we've switched.

Okay, good. So I have here a script editor. And I have a little script which I've written that does a very small amount of Sketch stuff here. So this script is targeted at the Sketch application, I wonder if I can make that bigger. Alright, never mind. So, you don't need to read this, but basically this is going to tell Sketch to create a new document and then put some graphics in it and so on and so forth.

So if I run that, you can see that it creates a new Sketch document, puts a little content in there, and so forth. And then the only other thing I want to show here is Sketch was implemented prior to scripting being available. So scripting was kind of put in later.

So nobody was thinking at the time about the fact that somebody might be coming in and changing things besides the user interface. But because Undo was implemented in the model, That all just works. When we added scripting, it's fine. You know, things that are done through a script are undoable the same as if they were done through the UI. So, okay, that's the end of the demo. And I believe I have one more slide here, which is just where to get some more info on this.

So there is a chapter of the programming topics document. I think it's called App Design, and it basically goes into a lot more detail on exactly these three concepts-- document, scripting, and undo. There's new for, I think, DP3 is an FAQ on NSDocument. People have questions. A lot of them tend to be commonly asked. These are some answers.

There's pretty good scripting documentation that tells you how to do script suites, how to handle scripting in your app, so on and so forth. There's various release notes that you might want to look at. And then, of course, there's the Cocoa reference documentation. So OK, now let's bring Ali up, and he can talk about text.

If you were at the Cocoa overview session, you saw Mike Ferris actually put together the text edit demo, and now we want to talk a little bit about the text system that he used in that demo. The text system, we have a fairly sophisticated text system in Cocoa. There are three major high-level features. First of all, it's international.

It was designed with being international in mind. It's Unicode-based. It supports inline input methods. It doesn't support every aspect of internationalization yet. For instance, you cannot type bidirectional text or vertical text in there. However, because it's Unicode-based and because the API encourages use of Unicode and other proper methodologies, if you use the text system, it's highly likely that your application will just work with bidirectional and even vertical text.

It's also flexible. It's got multiple replaceable classes in there. And we'll just talk about the major ones. And it has a wide range of intended uses. All the text you see in Cocoa applications, ranging from a text field all the way up to a large text view, for instance, the text area of Project Builder, which has colored text and it has a lot of specialized behavior, or the text area in HTML edit, which has even a totally different object model behind it, is built using the text system. It's also powerful. Even if you don't want to subclass and add stuff on your own, it has a lot of features out of the box. as Mike showed during the demo.

So there are two, you know, you can approach a text system casually and just use it in your application without doing anything else than just a simple usage. And I'll just talk about two of these. One of them is NSTextField. This is a class that represents, you know, all of those elements in that little window. The editable field, the password field, the non-editable field, those are all text fields. It's usually one line. Could be multiple, but it's usually one.

It's usually non-rich, but could be rich. And it's read-only or editable. You can use it for a lot of things. So you see both examples there. And these are subclasses of NSControl. What it means is when the user enters data and hits return, a target action method is sent so you can take action based on what the user changed. So it's obvious what the use is. It's for text fields and stuff, you know, little fields that appear. The other use is TextView, the other class.

This is for more sophisticated editing. Typically they're rich. You know, they have rulers, they have color panels, font panels, you can drop graphics in there, and so on. It's got a lot of the additional powerful features of the text system accessible directly in there. The good news about both of these cases is they're both available in Interface Builder. You know, you can say new application, drag a text field, drag a text view, and you can check a few boxes and most of the features are available.

Now, so that's the TextView class. Let's look at what's beyond TextView. We have the LayoutManager class. The LayoutManager is the piece of the text system that coordinates the layout of text and so on. And we have the text storage, which Mike talked about earlier, which is basically the back end of text, where the text is actually stored. And in fact, these three pieces form the model, view, and controller, which is what Mike just talked about. The text storage stores the text, the LayoutManager lays text out, and TextView displays it.

OK, so the NSTextStorage class, which is the model, the back end, it basically stores the text as an attributed string. There is a class in Foundation called NSAttributedString, and this is actually a subclass of that. NSAttributedString is basically a NSString, meaning it has Unicode characters in it. Becky talked about this on Tuesday. And then it's got on every character an NSDictionary of attributes.

And for efficiency, we put these on ranges of characters. Let me show you a picture. Here is a string which contains, I believe, eight characters. Now, because this is Unicode, we can say there's just eight characters in there, in here. If you're not talking Unicode and you're talking classic one or two byte type encodings, you know, this could be maybe ten bytes or whatever. You know, I don't know the exact byte count, but it would depend on what characters are being displayed. So there are eight characters here.

Now, the first one is an H with an underline. So its attributes for that range of one character is that it's got a color of light blue, it's got a font of Courier 72, and it's got an underline style that's solid. Now, if you look at the next five characters, the color there is light blue and the font is Courier 72.

We don't have an underline attribute in that case. By default, if there's an underline attribute, it means there's no underline. Finally, the last two characters, they don't have a color attribute, which would mean that we're using the default, which means white, actually, probably black, assume it's reverse. And the font there is Osaka 72.

Now, so there are three ranges here, three bags of attributes, and they apply to these ranges. Now, one other thing to say about attributes is you can have your own attributes in these dictionaries. For instance, if you want to have a special indexing attribute you add onto text, you can just add them into these dictionaries, call the attribute whatever you want, and you can add any of that. You can add any value you want. These attributes will be maintained at the text is edited, pushed around, et cetera and so forth. So it's, you know, you can overload these things and add your own information on any range of character you want.

So the layout manager is the middle piece, the controller. It coordinates typesetting of text. It reads text from the text storage, it lays it out into lines, and then it gives it to text view to display. So it's the middle coordinator guy. The other interesting thing about layout managers, it also stores information about the laid out text.

So if you want to ask, where is line one, or where is, you know, where are the characters one through twenty displayed on the screen, and so forth, or what's the bounding box that this text took up, this is the place to go. This has APIs to give you that.

One thing to note about Layout Manager, in fact the whole text system is, you'll note that there are APIs that are in terms of characters and APIs that are in terms of glyphs. Most of the time people use the term characters to mean both, but one, the distinction, the important distinction in our APIs, where we sort of have to be exact, is that characters refer to the elements in the text storage. Each Unicode character is a character. And when we say character range, we're talking about the range in the text storage. Glyphs are the displayable elements.

Glyphs are usually elements of fonts, and they're computed as a result of laying the text out. And the characters and glyphs are distinct. And in fact, one character might lead to two, three glyphs, or maybe several characters can be combined to show one glyph. And which glyphs get shown, display, which glyphs are shown basically depends on the font.

Let me give you an example. Most good text systems would take an F and an I, the two characters, and put them together to display the ligature FI. So the, the ligature is really just one glyph. So the character range that contains two characters corresponds to a glyph range that only contains one glyph. So, you know, if you look at the NSLayoutManager API, keep this distinction in mind, because it's important.

Finally, a little more detail about the TextView, the view part of the whole picture. It's the user interaction layer. It displays the glyphs. It also handles all the events, key up, key down, et cetera, all go to TextView. It also deals with the ruler, the font, and all the other color panels, and all the other user elements that basically the user is doing. It also turns out that if you want to have multiple columns, multiple pages, multiple weird areas, you just have multiple TextViews that are attached to the same layout manager.

Now one thing to note here is that NSTextView is a subclass of a class called NSText, which in turn is a subclass of NSView. And NSText is a sort of a legacy class that's in there. NSTextView is a class you should use, but for the whole picture, the whole API, you should really look at both TextView and text, and think of those as the combined API for TextView.

It turns out you can do most things with the text system using TextView, but for more sophisticated usages you would go beyond TextView and talk to the layout manager or text storage. So just to recap, text storage stores the text, layout manager lays it out, and TextView displays it.

and two other interesting text system components are the TextContainer class. TextContainers display, they basically describe the areas that text should flow into. In fact, you can use a TextContainer to describe a donut-shaped area, whatever you want. It basically describes the area. It turns out there is one TextContainer per TextView.

And in fact, it turns out that you can rip out the TextView from this equation and just leave the TextContainer and have a text system that doesn't display, but instead can be used to lay out a newspaper, for instance, in the back end without ever displaying it because it's going to the printers or whatever. So TextContainer is the part of TextView that describes the area.

And finally we have Typesetter. There is usually one instance of this. Typesetter's purpose is to get the glyphs and put them on a line. And then you can use the glyphs to describe the area. And basically do all the justification. So Typesetter is invoked by LayoutManager as a part of laying out the text.

Okay, so much for text. Now I want to talk a bit about performance. It turns out there's a performance session going on right now, which you're all missing, so we figured we might, we'd give you some of the interesting aspects of that talk here, especially how it relates to Cocoa.

So in the context of Cocoa application, and in general actually, Mac OS X as well, there are certain causes for performance issues. Memory, or the lack thereof, network or disk operations, or too much of them, too much drawing, and polling. So these turn out to be major concerns. It turns out that pure CPU usage is rarely the problem. I mean, typically if your application is slow, you're rarely going to find that it's because of lack of CPU power. But of course it happens, you know, bad algorithms can strike anywhere.

So let's talk about memory. One cause for problem is maybe one problem that you might not have on Mac OS is window backing stores. Both Carbon and Cocoa apps all have backing stores corresponding to every window that's on the screen. In fact, every window that's even not on the screen. So if you have a 1K by 1K window that's 32 bits deep, that's, I think, 4 megabytes of memory right there for that window.

And of course, this window backing store is something that's used to give you a really nice display, flicker free, and so on. Another reason is the custom heap management. A lot of applications might be doing their own heap management, especially on Mac OS, and this turns out to cause, this turns out to be a potential problem for apps running on Mac OS X. Finally, failure to release memory. You know, just leaking it or holding onto it too much turns out to be a potential problem.

So window backing stores, as I said, windows are by default windows. buffered. Also, NSImages, which is the image displaying component in Cocoa, NSImage will sometimes use caches, which are basically window backing stores, to cache images in. And again, you know, you load hundreds of images, that could add up to a few megabytes in your application.

Now, there are tools to look at these, and I'll mention these in a few minutes, but there are a few solutions in this area. You can make your windows one shot, which means when the window is no longer on the display, you can load a few images in there. It's memory is released, and every time the window comes back on the display, a memory region is created for it, and then the window is displayed. And you can assure that NSImages are not creating caches, and there are several ways to do this.

So one other solution that you might think about is why use the buffering at all? And it turns out that using buffering allows Windows to be flicker-free. If we didn't have buffering, when you do that lovely window moving on top of other windows, all the exposed regions would have to constantly be drawing themselves to keep up with, you know, keep up with the users moving. And, you know, that's a bit Windows-like maybe, and it's a bit, you know, not in the spirit of Aqua.

Custom heap management. Again, a lot of apps, you know, in order to assure that they have enough memory to complete an operation might be allocating large blocks of memory which they carve themselves. Maybe the memory that they used before in Mac OS 9 was not quite enough for them. It didn't do the right interrupt handling, whatever. It turns out that this is bad because it just causes fragmentation. If every subsystem allocated one megabyte for no use and carved it out, there are all these little pieces of memory that are not being used in the system.

And perhaps they're being kept hot because the custom memory management ends up touching all of those bytes. And another disadvantage here is that standard tools to track memory, which we'll show you one of, you know, it won't work. It doesn't know how this memory is allocated. So the solution here is just to use the standard memory system, the standard malloc that comes with the system. It's pretty powerful. It covers a wide range of uses. It should be good enough for almost all uses on Mac OS X. Finally, failure to release memory is the last point here.

As Becky mentioned, Cocoa introduces reference counting where objects can retain each other and so on. So one problem is that, you know, you simply retain something or you have a copy of it and you don't release it. Well, that's an obvious memory leak. You know, you have to release it. Another problem is sometimes one object can retain another object and that object in return retains me. So these two objects are retaining each other. They might be totally useless, but they're just sitting around not getting freed.

And to solve that, you really need to be consistent in how you do retains and releases. One guideline we use is if you have parent-child type things, you know, where you have a hierarchy of objects, typically the top level objects retain the lower level objects and the lower level objects, even if they point to the higher level objects, do not retain the higher level objects. Another case is loose connections.

For instance, in Cocoa we have delegates, outlets, targets. Those are typically entities pointing to objects. Typically entities pointing at each other. Typically those loose connections do not involve retains, meaning an object does not retain its delegate or its targets. Because those are all entities that are objects in their own regard.

So the performance tools to track malloc memory, there's object alloc and malloc debug. I believe we'll show you object alloc in a few minutes. To track all memory, meaning everything an app might be touching that includes all the shared frameworks, etc., there is tools like TOPS and PS, which you run on the command line. Now, if you run these and you see V size, which means virtual size, you might at first be shocked. You'll see numbers like 80 megabytes.

That includes all of the shared frameworks and all the other things that are shared across the system. So that's not really the number that's, you know, what your app is actually occupying. But looking at number and seeing whether it's growing or getting smaller and looking at trends at that number is still interesting.

Finally, the track window backing stores. There's no tool on DP4, no obvious, no easy way to do it, but Chris will show you a tool that's, I think, going to be released pretty soon. So quickly, the other reasons. Network or disk operations. These take a long time, relatively speaking, and you probably all know you've had to deal with these things. These might have an unpredictable effect on performance because sometimes the disk is slow, sometimes network is slow.

One thing to watch out for is on Mac OS X, user directories can be either on a local machine or they can be in a network. And we go to the user directory to read stuff like preferences, or you might put caches there or other documents. If you always test in the context of a local user, and then you might find that on the network user case, where the network access is much slower, you might find that things are just way slower and you weren't prepared for network accesses.

So. and the thing here is obviously you should avoid or delay or call us operations that touch the disk. For instance, if you're writing preferences out, don't write them out every time something gets changed. Maybe wait to write them out at the end. Cocoa applications actually write out the preferences when they're quitting, so you could just let the Cocoa system do it for you when you update preferences. There are tools, Sampler, I believe Chris might show that, and FS usage. FS usage is a command line tool which will show you all file system calls that a process or the whole system calls. whole system is doing. It's pretty entertaining if you haven't seen it.

I'm entertaining in a sad sort of way. Drawing too many times is another common problem. Sometimes in object oriented environments, because multiple subsystems might be doing drawing, two different subsystems might cause update of an element and you just might not notice, it might not be obvious. NSView, the abstract drawing class, actually provides facilities for managing and coalescing dirty regions.

So instead of causing a display immediately, you should call set needs display, which records in NSView that this region updated, and eventually it will display at the appropriate time. We have various tools, and again I think Chris might show one of them I mentioned, that show you displaying as it happens, so it gives you an idea of what's going on.

Finally, polling. Polling is bad. Sometimes polling is used, I think sometimes Mac OS 9 applications use polling more than, say, on Mac OS X. Polling is bad because it keeps applications awake, the kernel has to schedule them in, the applications memory is kept hot, and it also interferes with power management and with scheduling.

I mean, the kernel is trying to schedule applications, and there's an application that every tenth of a second says, anything happening? Anything happening? Anything happening? You know, you eventually, you know, you get, you can see how it could be a problem. So the solutions are, there are pretty good solutions in the system. There are event mechanisms both in Carbon and Cocoa that let you catch events when interesting things happen. Mouse down happened. Mouse move happened, et cetera.

Rather than you sitting there polling the mouse location. And there are also notifications that will tell you that certain things changed. Another thing is, even if you can't avoid polling, maybe you can do polling at key points. When your application becomes active, you could update the state of some certain thing that you're displaying.

Perhaps when your app is active, the chance that it's being displayed, changed behind you are very small, so it's not interesting to update. And Sampler and Tops will again show you the cases for polling. OK, so I will now invite Chris Kane on stage for a demo of some of these tools.

Let's see. In the short time we have, I don't have nearly enough time to go into any detail on these apps as far as how you go about to use them to solve particular problems. I just want to show that the apps exist and generally what they're about. The first app here I've launched is Sampler. and I am going to choose TextEdit. I'm going to sample the launch of Texted. And so what I've done is I have just hit the button that said Launch and Sample. And now it's done.

and what we have is a call graph on the left to the center of the window. And this is showing the call stacks that Sampler found the app in, if you will. What Sampler is doing is every, in my case, 50 milliseconds, it's going out to the other app, it's stopping it, it's going and plundering around in the application, finding out where all the threads are, what they're doing, and it's recording that information. And so what it's displaying in the call graph is the sort of coalesced call tree view of that, of what was going on.

Over in the call stack list, over on the far right, what's going on is Sampler has chosen the hottest frame, hottest node at every frame in this coalesce call graph to show you what's the hottest thing going on. What we're seeing here in this case is the app spent most of its time while it was sampling. It launched very quickly and then I let it run a little bit. And it has spent most of its time just blocked waiting. So that's what this is doing. We see NS application run.

It's looking for a next event. And a lot of internal routines here. We see CF run loop is being run. So we're going down into the layers of the system. And eventually we trap into the kernel and we're blocked in the kernel waiting for an event to come in, a user input event. Now I haven't clicked over here so no user input events have come into the app. Certainly not while I was sampling.

So, one thing I just wanted to point out while I was here is that it's very normal, very normal to see this sort of backtrace that if you find your app in the situation where Mach message overwrite trap is stuck in, essentially, that is normal and that is good. And we want apps to be very quiet, not doing anything while they're in the background, like text that's in the background. If I sample, again, here, let me crank this down to one millisecond.

So every one millisecond, stopping the app and sampling. Now, one thing to note is that I have not built a special text edit here. This is just the text edit that comes on the system. I don't know if there's any way for me to prove that. I guess you'll just have to trust me there.

But to sample an app, you do not need to specially build a profile version of the app or anything like that. And so what we see is, while I was sampling, all the samples, all 5,439 of them, are stuck in Mach message override trap, waiting for events to come in. So that would wake up, for example, when I click the window there and go and do some drawing and stuff like that.

So that's Sampler. That's just a very quick look. The best way to find out more about these applications is to go in and play with them and see what they do. The next app I'm going to show you is Object Alloc. Object Alloc is a way of looking at the memory usage of an application. I'm going to choose TextEdit again, and I'm going to choose the binary.

So here we see the Object Alloc window. The first button over here is the Start button. I'm going to start up the task. Now it's launching TextEdit. What we see here is the histogram of various categories of allocations. Object Alloc is seeing all the allocations that are done by the application and is categorizing them as best it can. In some ways it's more sophisticated, and in some places it really doesn't know how to categorize an allocation, so it just gives it a generic moniker.

Now the font is probably too small for you to see there, but the first column is a category, and the category name in the first row here is ZoneMalloc22. And what that means is just a generic allocation occurs. So we have a column that's the number of blocks, which are 22 bytes in length, that are currently still allocated. And the other most interesting column is the total column, which I've selected here and we're sorting on.

And that shows that 2,075 of these blocks, blocks of length 22, were allocated while the program was running. One interesting feature we've added since DP3 is that we've added a new column. We've added a new column. We've added a new column. And what's interesting about DP3, and what's interesting about Object Alloc, is that we understand some of the CF types. So in the second row, you see CFStrings collected, and it identifies these particular strings as the immutable ones.

And I'm going to go over it in the second tab here. And if I click on CFString, immutable, here it's showing me a list of all the CFStrings that are currently allocated in the application. So if I click on one, it's showing me the content. It's showing me the contents of the string down here, for example. There's a string with .global_preferences. There's a string with a path in it. Thank you.

So that also works for other types of objects, so CFArray, the mutable variable kind of CFArray. Here it's showing the debug description. This is an empty array. The count is zero. Let's see, is there one with something interesting? A lot of empty arrays are pretty common. There's an array with one thing in it which looks like a string, a path to the application I launched, in fact. And so on. So here's CF set, and here's a description of a nasty CF set with a bunch of stuff in it. So that's Object Alloc.

The last thing, and there are other things you can do with Object Alloc. I suggest running it, playing around with it a little bit. Here, I'm going to demonstrate this in a moment, what's going on when this happens, but you can scale the view, for example, sort by the different columns, and so on. The last thing I want to show, let me stop that.

is, let's move it over here, this new tool Ali alluded to called Quartz Debug. It might not be called Quartz Debug when we release it, but hopefully it will be released soon. It's not in DP4, but it goes in and talks to the Core Graphics server, the Windows server, Window Manager, and tells it to turn on various graphical debugging features. So I'm gonna, let's see, what... Let's turn on all of these.

So what we see, what we saw briefly there, is the bits of the window that are being redrawn are first drawn in yellow. And then they're drawn with their true content. So if I click on a button, for example, We see, it's hard to see that the button is actually being redrawn since it's so quick. Let me turn on the delay.

If we turn on the delay, We see the very labor-intensive process that graphical drawing goes through to produce a window as complicated as Object Alloc's window. So here we see the tab view being drawn. There, that background pattern is being blatted onto the screen.

[Transcript missing]

and so on. So turning on the delay allows you to see where you have redundant drawing. I'm going to turn that off. That's just too painful.

Okay, so we've recovered. But I've, I've, I've, so I turned off the delay, and now we're just, you know, every time the window has to become inactive, of course, we have to redraw all the controls because they're now gray instead of blue, and, and things like that. One thing I've noticed, as far as debugging here, is that if I choose a different column, you can see, if you look closely, that the whole outline view is being redrawn. And that's probably correct and okay. If I, you know, change the view around, the outline view is just drawn once. But if I change the slider here, do you see that? It's being redrawn twice.

Really obvious if I do it out here. Nope. There. Twice. And in fact, the slider is also being drawn twice, so that's a little more subtle, and you might not be able to see that going on up in the screen. So I probably have a bug here that when I'm readjusting the scaling, I'm over-displaying the system. I might have a direct call to the display method in there, for example, rather than doing set needs display and letting the app kit display system will take care of that for me. I'd like to call Ali back.

Where did he go?

[Transcript missing]

So examples of Carbon APIs you can use from Cocoa include Quick Draw, Apple Events, File Manager, Resource Manager, Text and Coding Converter, Speech, and anything else that comes from low-level Carbon or application services. And of course, Core Foundation. Now, high-level toolbox APIs.

The high-level toolbox is the fundamental drawing stuff that is in Carbon, and it sits in the Carbon framework bucket. Those, in general, are currently not available. You can try to call them, but in general, events might not work, the drawing might not be right. So at this point, this is not something you can do in the context of a Cocoa app.

Now, I said that you could pass basic data types back and forth, so obviously C types and structures, no problem. Those are all the same between the two environments. Now, there are APIs to convert other types. Some of the more fundamental types you might be using in your app are file paths or FSREFs or URLs. And, for instance, File Manager, a Carbon manager, and CFURL, which is in Core Foundation, both provide ways to convert URLs and paths back to FSREFs and FS specs and so on. So you could actually intermix those two APIs by doing these conversions.

And also, some Carbon APIs still take Pascal strings, and in the context of a Cocoa app, you might have NSStrings or CFStrings, and then you can use CFString or NSString conversion facilities to call down to those APIs. Now, I'm saying NSString or CFString. This brings us to toll-free bridging, which enables passing, which enables treating those two as the same. So what NSString does is some CF types are the same as their Cocoa counterparts. CFString is the exact same as an NSString.

Array, dictionary, data, URL, the same thing. And there are a few other classes this is true for. What this means is if you have some Cocoa API and it gave you an NSString and you have to call a Carbon API that takes a CFString, just cast away. It's the same thing, no problem. Okay? So this is -- thank you. So you can just pass these back and forth. Okay.

Okay, so much for Carbon. Now, as I said, our intent over time is to improve the bridging, and currently you might find that some areas are not properly bridged yet. And if you hit upon a wall, if you hit something you need definitely, please let us know. And finally, the last topic for today is programming Cocoa with Java.

As you know, Objective-C and Java are both the languages with which you can program Cocoa. And here I'm going to talk about some of the design flaws of what happens when you use Java to program Cocoa. You can access most Cocoa APIs using the Java language, and I'll explain why it's not everything.

Cocoa objects can be subclassed in Java. So if you have an NSView, which is a Cocoa object with an Objective-C, and you want to have a subclass of it in Java, you can do that. You can also pass objects back and forth between Java and Objective-C. So NSView is an Objective-C class.

It wants, you know, some object. It wants to have a window passed to it. You can pass a Java version of it. You can pass a Java version of it back and forth. It's all automatic. And your applications can either be 100 percent Java or you can make them hybrid, meaning parts of them can be Objective-C, parts of them can be Java.

So the philosophy we have in the Java APIs is that we want developers to be able to use the Java language to program and to create Cocoa applications. However, we want to preserve and expose the Cocoa programming model, because we have this Cocoa application model. It's one way, and you should be able to use that in the application.

But we also want you to be able to use Java paradigms and objects where possible and where it makes sense. One example is the Java string class. It's all over the place in Java. And in the Java side, it might be a better idea to use the Java string rather than use the NSString class.

And functionally, they're pretty much equivalent. The other goal we have is that you want to be able to integrate and use Java libraries as much as possible. Java network libraries, whatever else you might have, Java utility libraries. You should be able to use them in the context of your app. And this is pretty much confined to the lower levels, meaning at the UI layer, it might not work so good, but the lower levels, networking, et cetera, those APIs are all available to you.

So I talked earlier that, I said earlier that most APIs were exposed. It turns out almost all of the app kit is exposed using this name, com.apple.application. And then we have some of foundation exposed. When I say some, it turns out to be at least half of it, com.apple.yellow.foundation. Now the areas that are not exposed is basically areas where we decided that Java has an equivalent. And finally, there are additional frameworks, com.apple.yellow.scripting has the scripting functionality that is added onto the Cocoa frameworks. Now, we will rename these things at some point soon, so.

Okay, so most objects are exposed directly. We call these wrap. So NSView in Objective-C is the class com.apple.yellow.application.nsview in Java. Now I talked about the string class, which is not exposed. Those are morphed, meaning any time it goes to the other side, it goes to a change, it basically changes into an object of the other language. So NSString instances are converted to the string class in Java, and there are a few other classes to which this happens. And we repackage some functionality.

For instance, categories is an Objective-C feature which lets you add methods on top of an existing class. It's not available in Java. So in those cases, we either take the methods that are in a category and fold it into the base class, or we repackage them into a separate object. And C functions, which Cocoa has some of, are not exposable directly in Java, so we usually package them into a utility class, much like the math class in Java.

And Cocoa also has a bunch of structs and selectors, and Java doesn't have a concept of structs and selectors, and those are converted to Java objects as well. And as far as method name mapping, in Objective-C, method names can have arguments, keyword arguments, or keywords for each argument.

For instance, post event, at start, there are two arguments there, one between each colon. In Java, we convert that to post event, meaning we drop the other argument names, because often the main part of the name is good enough. And Java also allows overloading, which means you can have various versions of that. Sometimes when the name would be not very obvious, or sometimes when the second argument is as important as the first one, we tend to keep the whole thing, so set object for key becomes set object for key.

Finally, init methods, which are the constructors in Objective-C, in Java are just converted to constructor methods. For instance, the NSView init with frame method, which is how you create an NSView, in Java is simply NSView, which is how you create objects in Java. So those of you who are familiar with Java probably have tools to inspect and look at Java APIs, like JavaP and so on. One tool we provide on the system is this app called Java Browser.

It's really handy. It just shows you a browser up there of all the classes it knows about, which includes the Cocoa classes, plus all the other classes, including the Sun classes. And you can choose any class, and down below it will show you a nicely formatted API for that class. So it's a fairly handy tool if you're, if you want to browse through the APIs. Thanks.

Okay, so I think Becky went through the documentation. There's documentation on DP4, release notes and so on. The release notes are really quite handy. There's documentation in system developer documentation, Cocoa. You can also go to the website to see if there's updated documentation in any of these areas. We have example code in both system developer examples app kit and system developer examples Java app kit for Java applications written with Cocoa. And here's the roadmap.

Some of these talks have passed, but, you know, if you have a chance, if the facilities will provide to review them, you can choose to do so. Let's see, the localization talk is happening right after this. I think that's Mike talking about how to localize Cocoa and Carbon applications.

The Quartz talk is tomorrow where it talks about Quartz APIs that you can use directly from Cocoa applications if you want to. And the performance talk, that is pretty much wrapping up right now, I believe. So, okay, let's see. So I think we have about ten minutes. I would like to invite Mike and Chris back on stage for some QA.

And Becky, I think I see her there, too. Now, one, one thing, we have a brand new address, [email protected]. It works. So if you have comments and feedback on the APIs, new features you'd like to see added to AppKit and Foundation and such, please send, send us mail. Thank you.