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

WWDC05 • Session 102

Cocoa Today

Application Technologies • 1:05:24

Cocoa, with its mature, object-oriented APIs, intuitive design paradigms, and powerful built-in functionality, is the ideal framework for rapid application development on Mac OS X Tiger. This session will cover important trends in Cocoa development, key advances for Tiger, and the state of Cocoa today. You'll learn about techniques and advances you may have overlooked before, and get a better understanding of how to structure your application. See how you can take advantage of all that Cocoa has to offer.

Speakers: Matt Formica, Ali Ozer, Andreas Wendker, Mike Rossetti

Unlisted on Apple Developer site

Transcript

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

Hello, everyone. Welcome back after lunch. My name is Matthew Formica. I'm the Cocoa and Developer Tools Evangelist here at Apple Computer, and welcome to Cocoa Today. So people stopped me in the halls earlier today and were asking me, so what's Cocoa Today about? And I said, well, it's about Cocoa Today. And they didn't think that was very helpful, so I'm going to try and explain it in a little more depth here. Cocoa, as you know, is Apple's rapid application development framework. It's really the fastest way to develop new applications on Mac OS X.

And as for today, well, where do we stand today with Cocoa? We have a rapidly growing developer community around Cocoa. If you are a member of the Cocoa developers mailing list, you know how many people are on that list, and how you can get just about any obscure question answered, or at least someone will try to answer it, on that list. One of the reasons why the developer community continues to grow is because of all the great new APIs we continue to add to Cocoa with each new version of Mac OS X, including Tiger. Things like bindings and core data.

But with all the focus on Tiger, it may be actually easy to miss some of the broader themes in Cocoa, some of the things we've been working on across several OS versions of Mac OS X that are just now really coming to fruition. So what we wanted to do in this session is explain not only some of the high points of Tiger with regards to Cocoa, but also what are some of the design decisions that you should be aware of, some of the overarching themes that you should be implementing in your applications when thinking beyond just Tiger, but to Mac OS X and Cocoa as a whole.

Now, in part because of some of the great new APIs that we've got in recent OS versions, a lot of developers are moving to Cocoa, and they've been giving us great feedback about a lot of the features, in particular bindings and core data. So I just wanted to share a little bit of that feedback with you. Will Shipley, co-founder of Delicious Monster, had this to say when talking about bindings.

Matt Formica, Ali Ozer, Andreas Wendker, Mike Rossetti Now, in part because of some of the great new APIs that we've got in recent OS versions, a lot of developers are moving to Cocoa. So I just wanted to share a little bit of that feedback with you. Will Shipley, co-founder of Delicious Monster, had this to say when talking about bindings.

So a lot of code gets to be thrown away with Cocoa because the frameworks are doing more for you. He also had this to say, "Without Cocoa bindings, it would have taken another four or five months, maybe more, to finish Delicious Library." Another developer also gave me some good feedback.

Jerry Halls from Kronos, maker of Sticky Brain, a productivity app, said, "With Cocoa, we were able to accomplish a lot more, more quickly," pointing to the fact that with Cocoa, because you get so much functionality by default, you can spend your time on the value add, the part of your application that's really unique.

For those of you sitting on the fence, he had this to add: "Be bold. Take the leap." And one of my favorite quotes is actually from a blog out there from a Cocoa developer who sat down with Core Data and was just completely enthralled. He said, "I want to marry Core Data and have its children." So, people are very enthusiastic about Cocoa. Hopefully you will be at least this enthusiastic by the end of this session.

So what else are we going to talk about today? We're going to talk about some of the broad scope of Cocoa, as I've mentioned, some of the recent changes and directions, things you should be aware of going forwards. And we're going to also have a testimonial from a developer who has done the process of converting a non-Cocoa app to Cocoa. So with that, I'd like to turn things over to Ali Ozer.

Good afternoon. I'm Ali Ozer, manager of the Cocoa frameworks. Before we talk about the recent changes and directions, which is the main bulk of this talk today, I want to cover the design architecture and tools. Basically, what is Cocoa, and what's its philosophy, and so on. To talk about Cocoa, it's really interesting to talk about Cocoa's goals, because that's what defines Cocoa. The one way we define Cocoa is to say, simple things simple, complex things possible. You might have heard this before. It's basically how we, the design philosophy behind Cocoa.

We want to make things that are common to all applications, the common application behaviors, we want to make that easy for you, so you can achieve them with little or no code. However, things that are more complex, things that are unique to your application, the way you want to differentiate your application, those things we might not have built into Cocoa, but you can do them by either customizing the classes, the object-oriented designs we've given you, or by extending them by adding new things and so on. And we make those things possible. So you can write the basic functionality you get for free, and you can write the things that make your app unique on top of that.

Now, Cocoa is not a separate box. Sometimes when people are thinking object oriented, framework, et cetera, they tend to think of this environment that's boxed itself into a corner that's powerful but not accessible from the rest of the world. And that's not the case for Cocoa. It's not isolated in its own environment. And one of the major reasons for that is because Cocoa is implemented in and is accessible via the language called Objective-C. Objective-C is a thin superset on top of C.

It's a very thin superset, which means it can call into C. It can call into any library on the system, whether it's Carbon or Mach or POSIX or any other library that you get from the web. And it can easily interact with all these other subsystems because it's Objective-C and that's C.

Now, one thing that Cocoa doesn't do is to provide an API for every technology on the system. Sometimes people are surprised. Why can't I do this through Cocoa? We tend to-- we don't want to duplicate efforts. So we won't provide APIs where that API might just be-- it might be a wrapper or some basic duplication of functionality. We do APIs when there is benefits, such as abstraction, power, rapid development, performance. What I mean by that, for instance, is like NSWorkspace class.

We had an NSWorkspace class in Cocoa for pretty much the whole duration of Cocoa. Originally, that class was meant to interact with the workspace application back on the next machines. On some other platform, once upon a time, it interacted with the Explorer shell on that platform. And currently on Mac OS X, it actually talks to launch services or finder to get its job done.

Now, throughout all of this, developers who are using NSWorkspace never had to change their code, but the implementation just changed over and over, depending on the platform. And power and rapid development, if we can save you from writing 20 lines of code abstracted in one, that's where Cocoa's benefits come through. And performance-- so let me talk a bit about performance, since it is an important topic.

Sometimes, again, when people think object-oriented framework, they think inefficient. And again, with Cocoa, that's not the case. Cocoa was developed on machines that are far less capable than the machines of today. Four megabytes memory, that's equivalent to one nice dashboard image today or something. 25 megahertz processors. So those were small machines. Of course, Cocoa was a lot less capable back then, and it wasn't called Cocoa. It was the precursor to Cocoa. And since that time, we've added a lot of new features. We've also added a lot more computing power. We've always been vigilant about performance.

But one thing that has made Cocoa even practical on those machines of yesteryear is the fact that Objective-C, the implementation language, is object-oriented, but it has to have low memory overhead and low CPU overhead. It's very efficient. It's designed to be efficient, take very little memory, and also to have the message-sending system that, when caching is going on, is very, very efficient. So that makes it possible. And also in Cocoa, we have object-oriented techniques, and we use them to actually help with performance. An example is the way we hide implementation of, say, NSString.

When you use NSString to store your character string contents, you don't care whether it uses 8-bit characters, 16-bit characters. You don't care whether it's using a tree implementation or a flat array of characters implementation. The truth is NSString does all of these, depending on how it's being used. But again, depending on the situation, it does the right thing, and just gives you one model to work with.

And other techniques include we can cache in some cases where an underlying API might not, et cetera, to give you the correct performance. So with object-oriented techniques, sometimes you'll get a boost in performance that you might not otherwise if you actually had to write the 20, 30 lines to get the same job done yourself.

The API of Cocoa, the Application Programming Interface, also really helps define Cocoa because it's consistent -- it's got consistent naming and calling conventions, which really helps make Cocoa easy to understand, easy to predict, and easy for you to extend by using similar naming schemes. We like to call the APIs impedance matched. When you get an API from here and when you get an API from here, they're both Cocoa. They will plug in well together. You don't have, oh, 110 volts and 220 volts, and oh, oh, oh. So, you know, that's -- we like to call it impedance matching.

You'll see this over and over in Cocoa APIs. And the other thing is we have a small number of concepts such as delegation, outlets, target action that are used over and over, which makes Cocoa very powerful. And as an example, we recently added the bindings, a brand-new concept -- well, brand-new concept in Panther. And we immediately applied it to all the classes in AppKit so that it was widely used and that, you know, you could take advantage of it from any place where it made sense.

Cocoa is also universal. You might have seen the demos yesterday and heard the talk of this universal thing. I mean, part of it's because Cocoa's been through the hoops. It was originally on 6830 back in the day and 6840. It also was ported to RISC architectures and it was ported to the 386, 486, etc. RISC taught us how to be aligned correctly and x86 taught us how to go backwards and forwards. So we solved a lot of these problems early on.

Now, what makes Cocoa universal is the fact that the APIs are architecture independent. There's no Indian dependencies or architecture dependencies in the APIs. There are a lot of abstractions like NSString, again, as an example. With NSString, you don't care how your Unicode characters are stored, whether the two bytes are stored little Indian or big Indian. You're working with a higher level of abstraction. It's an atomic object that contains a string. Opaque objects, again, you're not in there dealing with the fields of a struct.

The objects are actually abstracted. You're actually hiding all that from you. And we have concepts like archiving where you can read and write objects and archives you create are Indian independent. The archives you're creating today and the archives you've been creating for the past five years will work on Intel, no problem. So that's the kind of abstraction that makes Cocoa universal. Now, let me talk a bit about Objective-C++ because this is a topic that interests many people.

We enable integration of C++ and Objective-C in the same source file. So you can actually use Objective-C and C++ in the same source file, and we call it a peaceful coexistence. We want to keep the capabilities of both systems intact. We want to keep the native ABI, the semantics, the performance intact. We don't want to change any of these.

So we keep both languages as they are in their standard form, but we let you call between each other. So one thing that means is we don't, for instance, give you the ability to subclass a Cocoa object in an S window, an S string, using C++. However, you can call back and forth between those. You can have instance variables of either type in each object.

And what this means is if you have a large body of C++ code, or you want to use C++ in your Cocoa project, that's all easily done. Just take the C++ code you're using in your project, and it gets most of the code. And it gets all developers, almost all developers, exactly what they want. It gets it done. Now a few words about Cocoa Java.

So the Cocoa Java is our APIs to make Cocoa APIs, our Java APIs to make Cocoa available to Java programs. And for the most part, this is transparent. Of course, a Java program you write this way is not cross-platform because it's dependent on Cocoa APIs, which -- and -- but for the most part, you can write a Java program. It is using Java APIs, and you can access Cocoa programs.

However, we have some downsides to this approach. And those of you who use Cocoa Java have probably noticed this and known this. The maintaining and setting up of the bridging isn't free. Every time we add a new class, every time we add a new method, we need to go and decide what the Java interface looks like, because we want to make sure the Java interface is good and it fits the Java guidelines.

The bridging itself is not also toll-free. It's not free for objects to cross between Java and Objective-C, so there's always a little performance hit. And finally, the applications written this way have slower startup times and larger footprints than their Objective-C counterparts. So when you're developing such an application, if you want to get it to the next level of performance, at some point, the truth is you want to maybe put aside the Java version and rewrite an Objective-C. So as a result of these, very few developers are actually using Java to program Cocoa.

And, you know, with that, we're saying that we will not make additional Cocoa APIs available in Java. So the ones that are available today, which is a large subset of AppCode and Foundation, but not the other frameworks, will be available. But any new APIs, any new frameworks, are not going to be available in Java.

Cocoa-Carbon Interaction, again, another topic that's of interest to a lot of developers. Now, developers want to be able to, you know, they have Carbon source bases, they want to start using Cocoa components, they want to migrate slowly, or they have Cocoa programs and they want to be able to use Carbon plug-ins, or so on.

This is what we want to enable. So what we support, so one thing we support is the non-UI code. Now, as I said earlier, Objective-C, C, calling conventions, all same, so you can call into any Carbon API which is non-UI. You know, you can call FSRefs, you can call launch services, all that.

Sometimes there's no, the impedance match is, you know, not perfect, so you have to convert FSRef into a URL or a path, but, you know, you do it, it's straightforward, no problems. Another thing that's supported is modal panels in the other environment. You can put up a Cocoa modal panel from a Carbon application and vice versa.

Now, also supported is just putting up windows in the other environment. So you can put up a Carbon window from a Cocoa application or the other way around. However, there are some caveats. Sometimes, you know, there are some edge cases or if you push the envelope, there might be bugs. Now, if you're trying to do this and you run into bugs, let us know, and these are things that we want to fix.

Now, there's also the area of things that don't work and they're not supported. That's basically hosting views within windows of the other environment. So you cannot put an HIV in a Cocoa window, you cannot put an NS control in a Carbon window. Similarly with sheets and drawers as well.

Okay, so before I start talking about, before we get to that section of the talk, just an overview of what the Cocoa frameworks look like in a simple architecture diagram. There are three core Cocoa frameworks, Foundation, Core Data, and Application Kit. Foundation is our non-UI framework, contains objects like collections, file manager, thread, etc.

Core Data is our new framework, it's new in Tiger. It gives you facilities for object lifecycle management, basically object persistence, undo, relationships, Andreas will talk about that in a few minutes. And the Application Kit, which is the UI layer of Cocoa, which includes Windows, Events, the text system, the document subsystem, so on. Now typically you don't use these frameworks individually, you just go ahead and use the Cocoa framework, and your app is a Cocoa framework, and you don't care about these three frameworks individually. There are other frameworks on the system, which all provide Objective-C APIs.

And provide good impedance matching with the Cocoa APIs. WebKit and address book are two frameworks that were introduced before Tiger, and they've been around for a while. And the last six are actually new in Tiger, and they provide APIs, rich Cocoa APIs, rich Objective-C APIs for you to use.

And one final word about tools. The primary development tool, of course, is Xcode. It has great support for Objective-C and frameworks. It has great support for debugging, great support for indexing, great support for editing, and so on. And also, new in Tiger, it's got facilities for class modeling and data modeling.

The other tool for Cocoa development is Interface Builder. And it's the fundamental tool for creating Cocoa user interfaces. Not only does it let you lay out your user interface elements, put a button here, put a slider here, you can also specify connections between them. So when this button is pressed, this object is tickled. You can specify the bindings between them and so on. And when you save your interface, it doesn't generate source code. It just generates an archive, which is then read back in at runtime.

And finally, we have the performance tools. These are clearly critical tools you should be using on your applications. They let you do performance analysis of memory, CPU, and so on. And you should definitely take a look at these as you're developing your applications. So at this point, to talk about the recent changes in directions, I'd like to invite Andreas Wendker on stage.

Thank you, Ali. My name is Andreas Wendker, and I manage the Xcode and Codata frameworks. So we are constantly trying to raise the bar for what Cocoa offers to you. And so in every release of Mac OS X, you find a set of new features and enhancements that we think you should seriously consider for your own applications, because they make them more powerful, more easy to develop, and easier to maintain. And of course, we can list all of the changes here, but Ali and I picked a few that you'd like to cover with a few slides each.

Let's start with bindings and core data. These are two of the larger new features we recently added to Cocoa. And they share a lot of goals. And the most important one is to just significantly speed up your development process. And they do that by taking control of a lot of the standard default functionality that every application has to provide. So instead of having to develop the same kind of infrastructure for every application again and again, you can just let the frameworks drive, and just get more functionality, more powerful, more consistent applications for actually doing less work, for writing less code.

Which means that you can focus on your own core problem of your application, and you get much quicker to market. The two technologies are very tightly integrated. They share a lot of the concepts. They're often used together. But it's important to know that they are really independent of each other. So Bionics were actually introduced in Panther and Codata in Tiger.

So what are bindings? Bindings automatically synchronize user interfaces. They make sure that without you doing anything special, the user interface obviously reflects the latest state of the underlying data objects. There are two parts to Cocoa bindings. The first part is a set of controller classes that you use to manage and access your model objects. They give you things like sorting and filtering. They give you tools to handle selections, including a convenient way to handle multiple selections or the different selection states in the UI.

And they even allow you to easily display and edit object relationships. The other part of the technology are the actual bindings, which define how you synchronize an element in the UI with an underlying data object. So most of the time, you set up bindings code-free in Interface Builder.

And what's really important here is that bindings aren't limited to object values. Bindings are not just a simple form filler to get a few values in the text fields. In fact, they are bindings for all kinds of parameters in your UI. You find things like bindings for enabled and hidden states of your views.

You find bindings for controlling display fonts and colors. You find bindings for table sort orders and table width, window sizes, even tooltips, titles of buttons, lots of other things. So bindings really give you control over the entire state of your UI. They aren't limited to just filling some form. forms.

Bindings are based on the model view controller paradigm and on three simple protocols that we introduced. K-value coding, K-value observing, and K-value binding. Key value coding allows you to access properties of an object just by specifying the name without having to know the underlying implementation details of the object. Key value observing allows you to register for change notifications so that you are automatically told if a property of an object changes. And again, you just specify the name of the property you want to observe.

and Kevin Binding pretty much combines the two concepts and creates a definition of what kind of property of a view you want to synchronize with what kind of property in a model object. And like I said before, most of the time you just set this up in interface builder. But you can also do it programmatically, and the key value binding protocol offers a few methods that you can work with for working with bindings, the most important one being the bindToObjectWithKeyPathInOptions method.

So this is the method that actually establishes a binding. It has four arguments. You send the method to the view you want to control. The first argument is the binding. It's the name of the property of the view you want to control, typically the value or the enabled state. The second argument, the observer specifies the model object you want to work with. So you can either bind directly to a model object, or more commonly actually is that you bind to a controller in between.

The third argument, the key path, specifies the property of the model object you want to synchronize with. And the options dictionary just allows you to specify a bunch of parameters to influence the behavior of the binding. The most important one is probably the so-called value transformer. A value transformer is a simple translator object that can transform values from one state into another one. So even if your model object and your view object don't exactly match, if they have slightly different representations of the data, you can just plug in a little value transformer to make the two work together.

If you would like to adopt Cocoa bindings for your own application, there are two things that should really help you greatly. First of all, we try to make sure that performance doesn't get in your way. We spend a lot of time optimizing the user interface to refresh the bindings. We are trying to make sure that we only redraw the portions of the UI that have actually changed. So if possible, for example, you just redisplay individual sales in a table view instead of redrawing the entire content.

The second most important thing is that bindings can very easily coexist with the kind of traditional code that you wrote in the past to control your user interface state. So you don't have to convert over your entire application to start making use of bindings. You can pretty much incrementally adopt bindings just by going from one part of the UI, from one window to the next.

And you can also very easily mix and match bindings with the kind of traditional code. So even if bindings are lacking a certain feature that you would really like for a certain view, you can just continue writing your own code for that, and use bindings for all the other things around it. So it really easily integrates with the traditional style of development for UI in Cocoa.

Let's talk about Core Data a little bit. Core Data is our object-oriented API to manage data models. Both in memory and on disk. We often refer to it as a fine-grained object graph management and persistence framework. So when you use CodeData, you get a lot of things for free.

Our signature feature is automatic undo and redo. That is always complicated to set up. And with CodeData, you get it for free. You get things like object value and state validation. And of course, you can do all this with generic data objects that we provide for you. Or you can plug in your own custom objects using your own custom code.

And to write out the objects to disk, we give you the choice of three types of file formats, or object stores, how we call it. You can store your data in SQL databases on top of SQLite, which is a very nice, lightweight, embedded database. It's an open source database we integrated in Tiger. You can store your objects in XML files. You can store them in binary files, pretty much in a keyed archiving scheme.

So what's interesting with Cocoa Data is that Cocoa Data owns the schemas for all the stores. So you don't have to worry at all about setting up the stores. Even in the SQL case, you don't even have to create the tables. Cocoa Data will do that for you.

So it's just really nice, convenient, and fast. It's a little bit problematic if you want to continue using existing file formats, if you want to continue supporting file formats that you created in the past. In that case, you will typically just not use the persistent side of the framework. You will focus on the in-memory side, still get undo and redo all the validation and the other nice things.

features for free but you will continue writing your own archiving and unarchiving code Let's take a look at the different characteristics of the three stores. The fastest and most scalable store is clearly the SQLite store. The reason is that with the SQLite store, we can pull in only the objects that are currently needed by your application into memory, but we leave everything else externally on the disk. So we only fetch objects from the database on demand.

With the XML and binary stores, we read the entire file at once, so your memory footprint is usually larger, and response times are a little slower. On the other hand, while the XML store is the slowest one, it's human readable, and it's also easily exported and imported by other applications.

One more thing about the access pattern for the stores. The XML and binary store are the atomic, or give you atomic reads and writes. So they are probably the types of stores you want to use in a typical document-based application. The SQLite store is more commonly used in cases where you have a fixed location for the data store, something like a library, maybe for music or photos, in the user home directory.

So for data to do its work, you need to give it a description of the data objects. You need to give it what we call a data model. Essentially, you have to go into Xcode, use the data modeling tools, and create an entity relationship diagram of your data objects.

So entities define the types of objects you have in your data model. And for each entity, you specify a set of properties. And we support three different types of properties-- attributes, relationships, and fetch properties. Attributes correspond to the simple values that are stored in an object, something like the name of a person or the color of a graphics object. Relationships correspond to references between objects of different entities. And here we distinguish between to one and to many relationships.

For too many relationships at this time, we only support unordered relationships-- relationships that are represented as NSSets, not as ordered NSServies. And fetch properties are something in the middle. You can pretty much think about it as a loosely defined relationship on top of an arbitrary query that is executed in your data store.

So in addition to just specifying the structure and all the names of the entities and properties, you specify a lot of parameters that refine the work of Core Data. In fact, the more time you spend refining all the other parameters, the better of a job Core Data can do. Just to give you some idea, you typically specify a lot of validation rules, something like the length of a string, minimum and maximum values of numbers.

You specify delete rules, which tell the framework what to do if an object gets removed from your data store. A good example is a person object. If you want to delete a person object, you usually also want to remove the address and contact information of that person object. You'd call that a cascade delete, and the delete would allow you to specify exactly that type of behavior.

[Transcript missing]

In the core architecture, there's a central point, the point that you most commonly interact with, and that's the so-called managed object context. The managed object context is a container for your model objects. You can think about it as something like a scratch pad, or the arts and crafts table, where you kind of put all the model objects in the shape and form you want them to be.

And then to write them out to disk, you hook up the managed object context to a persistent store coordinator, which will then, based on the model, map the objects from the memory into the external store, into the external type of file format you want to use. And to the UI side, you just typically use bindings and controllers to fill and populate the user interface.

So before I hand my clicker back to Ali, I just want to give you a quick breakdown of where in the Cocoa stack we added the different kind of APIs introduced for these two technologies. And most of the time, you don't really worry about this, because you just link against the Cocoa umbrella framework. But sometimes you have to watch your own dependencies if you have reusable frameworks, or if you, for example, want to write a UI-free command line tool with Cocoa.

So in Foundation, we added a set of general utility classes, for example, predicates, which are allowed to define search criteria for filtering and searching of objects, sort descriptors, and index set. Index set is an object that is highly optimized for managing selection information. We usually use it to pass around selection data, index information, and table views and arrays. And, of course, the value transform and the value coding observing protocols, which are very basic, fundamental, are also in Foundation.

In Core Data, you find all the object graph management persistence logic. And this managed object is the required superclass for all the model objects you want to manage with Core Data. I already explained the managed object context in the store coordinator. There are also a bunch of classes to represent the data model at runtime, so a model with entity and property descriptions.

And in AppKit, you find all the controller classes introduced by Cocoa Bindings. We have controller classes for single objects, for arrays, even for trees. There's even a convenient way to access user defaults from bindings. It's the NSUserDefaultController. And then the NSKeyValueBinding protocol is also defined in AppKit. And with that, I'd like to hand back to Ali to finish. Thank you.

Okay, Spotlight. As you know, Spotlight's one of the highlights of Tiger, and we really like to encourage you to use it in your applications. The central class for Cocoa is NSMetadataQuery. NSMetadataQuery basically is the class for performing Spotlight queries. It's bindable, meaning you can actually bind it to user interface elements such as array controller and table view and so on, or tree controller.

It also has a delegate to modify query results before they're actually displayed. So you can tweak the results and display them in certain grouping or certain categories. The metadata query object provides query results. It provides attribute values, so you can optimize it to only fetch values for certain attributes, value lists, so it will give you counts of values, and also hierarchically grouped results.

So, for instance, like the music lists on your iPod where there is, you know, genre, artist, albums, etc. Now, in this here, you might be wondering, isn't, you know, you've probably heard of the MDQuery APIs for Spotlight, and you might be wondering why we have a class in Cocoa to do this when this seems like, well, it's not really a class. Well, there are several reasons. One of them is the fact that the impedance match I was talking about earlier.

These are Cocoa APIs. For instance, these APIs are expressed in terms of NSPredicate or NSSortDescriptor so that they'll fit a lot better with the other Cocoa classes. In addition, these are bindings-aware. You can hook these up and display the results in a table view immediately, you know, without having to write any or just very minimal code, maybe.

So, you know, the fact that these are hierarchically grouped results is unique to metadata query. That's something you can take advantage of with these APIs. Now, we do an example in the system called Spotlighter. It shows you the various features I talked about. You know, you can do straightforward queries and it will find the results.

And just by hitting that tab, you can actually look at the results in a grouped fashion, in this case, you know, grouped by file type, grouped by size, and also notice that when it groups by size, it actually collapses the every kilobyte together, so, you know, you're grouping by kilobyte sizes. So, again, uses that API.

It's a good example of that API, if you want to take a look at it. So, next topic I want to cover is error handling. Now, error handling might not seem like such an exciting, sexy subject, and it's something, you know, oh, yeah, error handling, that's just, you know, yeah, we do error handling. Well, it is -- we are very excited about error handling, so I want to talk about it.

We introduced NSError as a new class in NSPanther, and we've greatly enhanced in Tiger. Now here, when I talk about error handling, I'm not talking about, let's get every API in Cocoa to return error codes. That's not what we mean. What we mean is we want to get the APIs which might have user impact, where the user should be alerted.

We want to get those cases right. So our goal is to provide the user with polished, informative, well-crafted error messages. In addition, we want to handle common cases out of the box. There are a lot of errors that occur very commonly, you know, errors associated with maybe reading files, writing files.

Those are very common to many applications. So we want to handle those for you, and you don't have to write any code for that. So, for instance, here's an error alert you might get in TextEdit in Tiger. You'll notice that it's, you know, a fairly nice error panel.

It gives you a file name. It gives you what happened. It tells you why it happened. It even gives you a helpful suggestion as to how you might fix it. Now, TextEdit -- which is a fairly small app. It's not even NSDocument-based yet. We've been planning on doing this, but it's not yet.

You know, it gets this functionality with one line of code. Now, if it was NSDocument-based, it would get it with zero lines of code. But anyway, one line is not too bad. And, you know, you get this error message when you cannot read a file. Similarly, if you're running in French, you know, the frameworks provide you with the French version of the error panel as well. So you get automatic localization.

[Transcript missing]

So we've -- clearly, this error stuff becomes a lot more handy when there are more classes that return errors, and we've added a bunch of them, NSString, AttributedStringData, et cetera. Now, whenever you're reading and writing files, these will return NSErrors, so you can actually go ahead and then process those.

KeyValueCoding has had an error returning method for validation, so when the value that the user type goes to the model object, if the validation fails because the object is out of range or it's invalid, you know, you get back an NSError. And similarly, NumberFormatter and DateFormatter now have new methods in Tiger to let you get back errors when parsing of, say, a date fails.

Now, from NSServer to NSDocument. NSDocument also has some exciting new features. One of them is error handling. I already mentioned that, and I won't talk about it anymore except to mention that tomorrow there's an advanced document techniques talk tomorrow morning, I believe, where Mark Petrelli will cover the error handling and show you how it works. NSPersistentDocument is a subclass of NSDocument. Now, those of you who have used NSDocument know that the way you use NSDocument is you subclass it and you add your code to read and write the document contents, and everything else is handled for you.

With NSPersistentDocument, everything is handled for you, so you don't have to do anything. It's because it uses core data behind the scenes and, you know, basically saves your document for you in the format you choose. So I won't talk about PersistentDocument other than saying that. The one final feature of NSDocument is autosaving, and again, Mark Petrelli will show this tomorrow, but let me just talk about it because it also is an exciting new feature. It lets NSDocument-based apps periodically autosave open documents. And not only are you saving open documents, you can also even save untitled documents. So the user launches their app, they type away for eight hours without saving, and the power goes out.

Well, if you use this feature, they'll be happy because next time they launch the app, they'll say, "Hey, there's an unsaved document." Now, it takes one call to enable this set autosaving delay where you specify how -- what the delay is before the document is saved. So, you can see that the document is saved. We tried to make it so you don't have to call this at Different applications really want different behaviors. Some applications might want to set this to a bigger value. Some applications might want to customize the way they autosave.

And many applications probably should provide a UI and let the user choose whether autosaving should be enabled. So you'll have to call this with the appropriate value. There are a number of other related methods as well for autosaving. For instance, you can customize the way autosaving happens and not use the default way that we do it.

We have some changes in NS Text. If you were at the text talk at last year's WWDC, Doug Davidson did a great job of covering these. I'll just highlight some of the important ones here. We have support for a lot more document formats and also document properties. Now we have a lot more complete set of document formats we support. The ones that we've added in Tiger, we can now do a much better job of reading HTML, we can save HTML, we can also read and write web archive, which is HTML with images and other attachments, and we can read and write Word and WordML documents.

Now, so this means, for instance, in TextEdit, which is a fairly simple client of the text system, you can type, type, type rich text and save that as an HTML document. And you can open it, save it, open it, save it, et cetera. And it's losslessly being saved and restored. Now, because the HTML document saving, there are so many options that different people would want to apply, we actually have some ways to tweak, change the way the saving occurs.

You can, for instance, decide to use style sheets or not, and so on and so forth. You can decide to lose white spaces or not. In TextEdit, if you go to the preferences panel, you can globally set the way TextEdit saves HTML documents, and you'll see the options. You specify what kind of HTML, what the styling is, what encoding to use, and so on.

So as I mentioned, the text system now has support for document properties like author, subject, et cetera. We will read and write these metadata in all of the text document formats, except for plain text, which doesn't have support for them. The plain text format doesn't have any place to put these.

And in TextEdit, there's a document properties panel, which lets you specify these, and it just puts them out to the text document. Now, one reason I'm mentioning this here is because I want to encourage you to think about how you can support metadata like this in your own applications and your own document formats. Not just text, but any other document format you might have. And then provide appropriate UI so the user can save them, and then your importer can import them. And this makes your documents a lot more easily searchable and findable.

So other changes in the text system I won't talk about, but there is now support for tables, there's support for lists. This, of course, also enables us to have the better HTML support we now do. There's support for multiple selection. You can now select a column of text if you want, a rectangle of text, or you can actually do a search in the Find panel and find all occurrences of a certain word, for instance, and modify it. There are now standard panels to support all these features at the user level. And there's also improved text layout for complex international scripts. Speaking of internationalization, we've added two new classes and updated some of the existing ones, and let me just touch up on those.

NSLocale is a new API. We've never had a locale API. We always use this model of an NSDictionary which holds locale data together. This is a new class, and it's really there as a basis for future improvements. Right now, very few classes, only some of the new APIs we've added, uses NSLocale. So you can use NSLocale in those APIs, or you can ask NSLocale for various locale data, is what you can do. And the existing locale arguments in our API still expect the old style NSDictionary instances. So there's a bit of a transition period there with NSLocale.

NSCalendar is a new class which does all sorts of calendar operations, compose, decompose, date components, date arithmetic, et cetera. It's not really designed for creating your own instance, your own subclasses of NSCalendar, but it does have support for the major calendar systems in the world. So you can actually create calendar instances for . I'm going to show you how to do that in just a moment. So you can create a calendar instance for a number of different calendars.

And you can ask it questions like, how many days are there Here you're asking how many days are there in the month that we're in today, and the answer will be 1,31 is the range of days. Or you can ask questions like how many, not shopping days, but how many days till Christmas, which is the next question.

Date formatter is an existing class, and we've enhanced it a great deal. It now uses ICU, the International Components for Unicode Library, for doing most of its work. And what this means is the format string has been upgraded to accept new format strings. Now, because the change is somewhat incompatible, and we don't want to break applications, we made it so that you only get the new features if you actually explicitly ask for the new formatter behavior, which you do with this call here, set formatter behavior.

So we encourage you to do that for your formatters, where you really aren't using the old APIs in a way that would be incompatible. Just do this, and suddenly your formatters work for all localizations and will be a lot more capable. The way a date formatter works is you can specify the style of date and time. You can specify it separately, short date, long time, et cetera. Or you can actually go ahead and use format strings like you could do before.

Number formatter has gone the same sort of transformation, now uses ICU. And again, to take advantage of it, you have to make a call. And once you do that, you can ask for the different styles, decimal currency, et cetera. And the last one is sort of cute, and it even actually works in other languages.

So you can have it read it out to you or something. And both date formatter and number formatter now have APIs which let you convert from string to date, date to string with just one call. So a while before, the API was geared more towards being used with cell. Now it's easily -- you can use easily to convert numbers and dates to strings and back and forth.

Speaking of string, I'm just going to reemphasize something I've said many, many times before. With get off C string APIs, and we're finally deprecating them. I'll just explain what this means quickly. These are the APIs in NSString which do not specify an explicit encoding. So they interpret the bag of bytes, the C string, you know, the char star, to be in the string. And then encoding, which is dependent on the user's language. So this means that your program has ambiguous behavior.

If you don't test in some edge case languages, your program might work, but it might break, so on and so forth. So these APIs have been -- in general, they're not a good idea and we'd like to -- we've been discouraging them, and now we'd really like to say don't use them anymore. So it's these kinds of APIs. The last two are also in this boat because they actually interpret a file in the user's default encoding. So they're as dangerous as the C string APIs.

Thank you. The methods you should be using are methods we've been introducing both throughout Panther and also Bunch and Tiger. They're APIs which take an explicit encoding argument. So you say C string using encoding, so on and so forth. The last two, for instance, will-- you don't specify an encoding, but these try to guess the encoding and return the actual encoding to you.

They're right now not very sophisticated, but over time, they will-- our intention is to make them a lot more capable about sniffing the encoding used in a file. Keyed archiving. This is another thing that we've actually introduced a while ago, and I really want to emphasize the use of this class.

Keyed archiving is NSKeedArchiving, NSKeedUnarchiving, those classes as opposed to NSArchiver, which is something we've had for a long time. Keyed archiving enables creating archives which are a lot more robust and a lot more flexible than what we had before. So before, when you wrote a bunch of stuff out, you would say, write this int, write this string, write this bool.

And on the way back, you'd have to say, read the int, read the string, read the bool. If you read them back in the wrong order, it was disastrous. You couldn't really put new keys and things in there because old systems wouldn't accept them and so on. It's like walking around with a box of punch cards and when you drop it, you're dead. The order is gone and you don't know how to resurrect things anymore. The new way with keyed archiving, you basically say, write this int and you specify the key.

That's my age. Write this string, it's my name, and so on. And on the way back, you can ask for them in any order you want. You don't have to ask for all the keys. There could be extra keys in the stream that you don't care about. I mean, it makes a lot more sense, right? And that's why we added it. So with this, you can actually save documents in a new system, read them back on the old system, no problem.

We even have a feature in keyed archiving where if you have a new class that you've introduced and you're putting instances of that class in the file, you can specify as a hint the name of the class to be used on the older system if this class cannot be found. So if you have some less capable class in an older system, you can write out the keys that the less capable class would accept. So you can actually get your file to load. to load with some sort of fidelity on the older system.

VoiceOver, again, it's a highlight feature of Tiger, and you hopefully saw a demo of it yesterday at Bertrand talk. It's the built-in accessibility interface for disabled users, and it's ready to go right out of the box. You can either enable it when you install, or you can just hit Command-F5, do it now, and you'll see it start to work. Turn off your sound first.

It makes use of the accessibility APIs, which we added in Jaguar. Now, the accessibility APIs did make their appearance in Jaguar, and they were fairly thorough, and then since then, we've been adding to them. Recently in Tiger, the big change we did there was to add the ability to apply attributes to UI elements.

and to arbitrary accessible UI elements. So what this means is you no longer have to subclass UI elements to add some of these features. An example is, you can now add a description to any UI element. This is useful, for instance, for a button which just has an image on it. Clearly, a button with an image cannot be read back to the user through voiceover. However, if you attach a description to it, that description can be read when voiceover is enabled.

Another useful attribute like this is the linkage, the linked UI elements attribute. In mail, you have the table of contents on top, you have the body of the mail message at the bottom. It's nice to know that there's a linkage from here to here, so the voiceover can guide the user to go to this next field.

Although, maybe in the keyboard navigation, it's not the next UI element when you're tabbing through, for instance. Interface Builder also has support for editing these attributes. So, in Interface Builder, you can select your button, and you can go ahead and specify the description for it right there and save it out. It's really very easy, and it's really something, you know, if you have a button with an image, no text, you know, just consider doing this one extra step to make your app a lot more accessible.

Let me talk a bit about NSColor. Once upon a time we had this concept of calibrated colors which were device independent. And then for the longest time this didn't work. Where they were device dependent. And in TIGER they work again. So they're device independent. So colors you create with calibrated red, green, blue, or calibrated gray, or calibrated hue, saturation, brightness, those colors now return calibrated colors. And what we mean by that here is they correspond to the generic color space in quartz which is basically another very sophisticated way to get device independent color. Color that looks right or color that looks similar or the same on different devices.

Now, in addition to this, in addition to just the two device color space and color space, we now have the ability to have arbitrary color space sport in NSColor. There's a new class called NSColorSpace. It has predefined . In addition, you can create these color spaces from RCC profiles or ColorSync profiles.

and once you have one of these color spaces, you can go ahead and create a color, just create this color with this color space and specifying the floating point components appropriate for that color space. Now we bubble the support all the way up to the user. In Tiger, in the color panel, you might have noticed that there's a new little button to the left of that slider over there. That button, when pressed, will put up a list of color spaces that are appropriate for the currently chosen model. So in this case, generic RGB, device RGB, and sRGB, and maybe the one for your current device.

Now the implication here is that for the user, the user can actually now select these colors. They can drop them in your documents. For instance, if you're a drawing application, these colors can be there. Now if you save your documents using keyed archiving, you're in great shape, because these color space information will be saved out. On older machines, it will be properly ignored, but the user will still get the right color. On newer machines, of course, it will be used.

If you're using archiving to save your document format, the user will still see the right color, but we have to save it without the color space, because we can't support this new feature on the old archives. So there's another reason to move to keyed archiving. And if you're using some other document format, whatever, this is something you should be aware of. It's probably a good idea for you to somehow start saving the color space in your documents.

Okay, so, so far we've been talking about stuff that you should be doing, and now a few words about stuff you shouldn't be doing. One quick thing is 64-bit. As you know, in 64-bit, we don't have to have 64-bit support at the high-level frameworks, only the system framework. But in the 64-bit world, an int is 32 bits, a pointer is 64 bits. Therefore, an int and pointer are different sizes. If you ever make the assumption they're the same size, that breaks in the 64-bit.

So another assumption about resolution dependence. As you know, almost all the measurements in Cocoa APIs, except for window frames, are in terms of points. And points are 1/72 of an inch, roughly. So every time we specify these measurements, they're in terms of points. And it so happens that we assume on all the devices, one point is equal to one pixel.

You can imagine, as we move to higher resolution displays and so on, that one point might start covering two pixels, or one and a half pixels, and so on. And therefore, if we want to get truly resolution-dependent drawing happening in the future, it's nice never to make this assumption that one point is equal to one pixel. So all the measurements, all the NS rects and sizes that pass around, you know, assume those are points, not pixels.

And assuming APIs return things other than what they say, a simple example of this, an API might say it returns an S dictionary, but you discover, hey, it returns an S mutable dictionary, so maybe I'll just mutate it. That's a bad example. I mean, that's a good example of something that's bad to do. Don't go mutating such dictionaries. Another recent example that we saw here was the user defaults change.

User defaults now saves its files in a different format, which started returning not mutable, immutable dictionaries and such upon reading back, and some applications were actually bitten by that because they assumed they could mutate those, which, of course, is very dangerous because they're actually mutating the user defaults data structures. Another thing you should not be doing is drawing faster than 60 frames per second.

I mean, you know, if you can draw it, sure, it's a great thing to be able to say, you know, this app draws 300 frames a second, but you're really doing too much work and, you know, wasting CPU or GPU resources there because the user can't see it.

In Tiger, with the Call List Updates feature, if you're drawing faster than 60 frames a second, your drawing will be stalled while the drawing is -- the previous thing is being -- the previous drawing you did is being flushed to the screen. Now, this is only true for applications which have been linked on Tiger.

So for previous applications, for compatibility purposes, you actually don't get this. However, if you use Quartz Debug application and you can play with these things and you can check your app to see if your app will be impacted by this. So basically, you know, no need to draw faster than 60 frames a second. You can do computations and so on, but, you know, make sure you -- you gait yourself as you draw.

And there's a release note on this topic. And one final thing you should not be doing is using private APIs, you know. It's like we saw -- we see discussions of private APIs sometimes on the mailing lists, and Objective-C is great. It's got great introspection features, make it easy to find what private APIs we have.

But every time you use private APIs, you're using something that's undocumented, we might change it at any point, it might break, it might have some side effects. It makes life difficult for both you and us. So it's a good idea to avoid those. Let us know what APIs we're missing so we can add them.

And some universal considerations to be aware of. But first, actually, I would like to ask a question. So how many people had the chance to try their apps under Intel? Is there -- Yeah, there's a few. I heard downstairs that there's a universal compatibility lab in the cafeteria area.

You can just go there and compile your application. They have a bunch of machines, a bunch of engineers to help you out. I hear there's a good bunch of good success stories, you know, some with no tweaks, some with one or two small tweaks. So, you know, just if you get a chance, definitely try it.

Now, I'm just going to talk a few things about, you know, just add to a little bit what Simon said yesterday if you were in Bertrand's talk. The biggest issue with Universal that we've seen is basically file and network data byte ordering issues. You know, examples are UTF-16 files.

They have two byte entities. They can be little or big Indian, and, you know, you're making the assumption, oh, it's big Indian, and it turns out it's really little Indian. Files with ints and structs, you've actually dumped an int in there, or a struct in there, or bit fields in there, and so on. That's another sort of thing.

That's another source of problem. Possible solutions here, again, include stuff like if you use XML files, those are human readable, and for the most part, unless you write data in them, they are going to be Indian safe, Indian independent. The keyed archiver and the archiver classes, those are Indian safe. They do the right thing.

Now, if you already have data structures you've written out, and, you know, let's say you've written them out in big Indian format, and you've got to read those old files back in a little Indian machine, you can use the functions in nsbyteorder.h. They let you do things like-- Read a big Indian int from this slot.

And those functions are actually very fast. They're usually one or two assembly instructions, and on the right architecture, they actually vanish, because they're inline functions. So very small overhead. And of course, I'd like to encourage you to use the appropriate high-level APIs. For instance, if you use an S string to read and write Unicode strings to files, you never have to worry about Indian-less issues. Similarly, if you use Core Data, for instance, to read and write your documents, again, you don't care about the issue at all.

Other universal considerations. One thing, I don't know if you know how, GC4O, on the, to build universal, GC4O is your compiler. GC4O is a more strict compiler than GC3, and it will give you some warnings and errors in your code if you had some. Now, the good news is, of course, most of the time those warnings and errors are actually warnings and errors in your program, so it's a good thing to fix, but it might actually be something you encounter as you do, you know, move over.

Direct use of OpenGL, bitmap context, et cetera. If you're manipulating bitmap formats directly, there might be some end use issues. We've seen a few examples of these. Now, there are many potential bugs and undefined behaviors that don't exhibit themselves on PowerPC, such as uninitialized variables, invalid memory accesses. Those might not be a problem in your program today on the PowerPC, but on Intel, due to different, you know, memory addressing, whatever, you might get errors. Integer shift left by 32 is undefined. It does one thing on PowerPC, different thing on Intel.

Integer divide, you saw this yesterday. On the PowerPC, you get the zero, which, you know, well, you know, it's the wrong answer, but it doesn't crash. On Intel, you know, it crashes, so that's, you know, dividing or modding by zero is bad. For Objective-C specific, probably the biggest thing in Objective-C got you is the fact that if you send a message to nil, as you know, that just works, and it returns nil or zero.

But if you send it and the return value is a floating point number or a double or a struct, on PowerPC, you might, you will get zeros when the struct is smaller for floats and doubles, but on Intel, you will actually get back garbage. So if you rely on that behavior, you know, that's something to clean up, and this is, you know, this is something we've also seen in a few programs. Okay, so that's it from my part. Now I'd like to invite Mike Rossetti of Intuit Software on stage to talk about his experiences. Thank you, Ali.

Thank you. I'd like to tell you a story, a story involving moving a phonebook age application. Everybody know what the phonebook is, right? The phonebook age application called QuickBooks Mac into the modern Cocoa era of Tiger. Before I do so, I have two things I want to say about that. First of all, it's not going to involve breaking any body parts. The second thing is it's a dubious distinction being invited to explain how you can move a tough case application that's so old into the Cocoa era.

But a bit of a

[Transcript missing]

All right, so how did we do it? First thing we had to do was get it buildable and running. And the way we did that was by using MetroWorks Code Warrior. We made it carbonized by using Power Plant mostly. We aquified the user interface. We did a little bit of refactoring mostly. We just groomed the code.

We introduced Core Foundation where we could. That was the first year. The second year, the really important thing that we did was introduce Carbon Events. Made it pure Carbon Events. We added a few new features. We started using C++ in the standard library. And yes, C++ works very, very well with Cocoa.

Last year, we took advantage of Apple's Carbon and Cocoa technology because we had a lot of Carbon windows, a lot of Carbon technology in there, and we couldn't just throw it all out and rework it, especially because of the multiple levels of callback. So we used the Carbon and Cocoa technology, helping Apple debug it in the process, by the way. And moved over to Xcode, moved over to Interface Builder, and adopted several other enabling and bridging technologies. It was the next year that we found ourselves able to

[Transcript missing]

and next year we're pretty optimistic about being able to move over to core data.

Okay, so what's the bottom line? As you old-timer Mac appers out there will understand, it's the framework that makes the difference. It's the Cocoa framework that's made this much easier for us to do. The environments play nicely together. It's fun to use this stuff. And once you've embraced the Cocoa framework, you're able to move much faster together.

Now, what I'd like to do is ask the QuickBooks team to stand up. Right down here, Lucienne, Brooks Bell, Steven Friedrich, there's Keith Ray. You're welcome to talk to any one of them and get details about what the challenges have been that we've had to go through as we've moved to Cocoa.

And the moral of the story is, it's a lot closer than you may expect, and the benefits are terrific. I'd like to thank the Apple Engineering Group for not only making this a great experience, but also for making it a great experience for us. Not just making it fairly straightforward to do, but making it desirable to do. It's fun to do this stuff.

Matthew? Matthew? Thank you so much, Mike. So there are other resources for you to take a look at this week. There's the WWDC portal that's live this week with a lot of sample code and other documentation. I am the contact for Cocoa and developer relations. Feel free to send me emails with the feedback and features you want to see in Cocoa.