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

WWDC01 • Session 138

CoreFoundation Overview

Mac OS • 51:26

CoreFoundation offers a rich set of C APIs that provide basic data types, collections, user preferences, bundle and plug-in handling, internationalization support, and low-level event handling. These APIs are used extensively within Carbon and Cocoa, and CoreFoundation types appear in many other APIs. An overview of CoreFoundation and details on advanced services such as CFBundle, CFRunLoop, and CFMessagePort are presented.

Speakers: Chris Kane, Doug Davidson

Unlisted on Apple Developer site

Transcript

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

I'm Mark Turner. I'm the Carbon Technology Manager in Worldwide Developer Relations. CoreFoundation, as the name implies, provides a fundamental set of system services that are widely used throughout Mac OS X. And they're available for your use as well through both Carbon and Cocoa and any other application running on Mac OS X.

And a subset of these services are also available to Carbon apps on Mac OS 8 and 9 through CarbonLib. So, this morning we're going to get a great overview of some of the services that you might like to take advantage of in CoreFoundation. And to begin with, I'd like to introduce Chris Kane from the CoreFoundation team to start off our overview. Welcome, Chris.

Welcome. This session will be an overview of the CoreFoundation framework. It's going to explain what it is, describe some of the functionality it contains, and review some of the general concepts of usage of CoreFoundation. I'll begin with an overview. CoreFoundation is a low-level framework within Mac OS X. It's used to implement Mac OS X and contains functionality that you can also use in your frameworks and applications, as Mark said. Both of the higher-level frameworks, Cocoa and Carbon, use CoreFoundation quite a bit.

Part of CoreFoundation, as Mark said, is also available on Mac OS 9 and 8 via CarbonLib. This was done to ease porting of carbonized apps to Mac OS X and to bring some of the features of CoreFoundation to the libraries and applications on 8 and 9. For similar reasons, part of CoreFoundation is also available from Darwin, or within Darwin.

The CoreFoundation APIs are C APIs on Mac OS X. Through CarbonLib, they are also available in the languages supported by CarbonLib. There are also C++ wrappers for CoreFoundation in Apple's C++ frameworks for Mac OS X. Finally, I'll briefly note that CoreFoundation is often simply just called CF, and I'll probably slip up during my talk and use that abbreviation myself, so it's good for you to know right off the bat. Now, why did I call CoreFoundation a low-level framework? Well, partly that is due to where it sits in the overall organizational structure of Mac OS X. Here we see the usual simplified diagram of the structure of the system frameworks on Mac OS X.

CoreFoundation slips in as part of the core services umbrella framework. But I also called CoreFoundation a low-level framework because it deals with some of the most basic building blocks of your applications and your frameworks. These are the data structures that you use to store information in your application. CoreFoundation provides several basic opaque data structures that you can use rather than having to write your own.

And CoreFoundation also provides several higher-level application services, which are built upon the basic data types. And again, Apple system applications and system frameworks within Mac OS X use these facilities quite extensively. One of the key aspects of CoreFoundation is that it does not provide any graphics or media-related features. In the architecture of Mac OS X, graphics and fonts and sounds and those sorts of things are introduced in higher-level frameworks, frameworks at a higher level than CoreFoundation within that architectural diagram.

So let's begin by looking at some of those basic data types. We start with CFString. A data type representing strings of characters. Strings tend to be one of the most common data structures in an application, and in Mac OS X, CFStrings are certainly the most common CoreFoundation data type in use. Conceptually, a CFString is an array of Unicode characters. However, because the implementation is hidden behind the opaque CFString type and its functions, a CFString can be smart about how it stores those characters and use 8-bit encodings if possible or do other tricks for performance.

This takes strings beyond the traditional domain of, say, an array of 255 characters, as in Pascal, in some encoding that is currently in use in the system or in the application. By packaging up the characters, the length, and a fixed encoding in one type, use of strings in an application is simplified. And this makes things like internationalization easier.

Plus, by making the structure and nature of a string more predictable, passing and sharing strings among different parts of an application and frameworks is made much simpler. CFString has become the way to pass string data between library APIs, framework APIs, and applications in Mac OS X, and is a primary way in which strings are just simply stored within an application as well. And as new APIs are introduced, they are going to use CFStrings as their parameters and return values as well.

Now, CFString is an abstract data structure, so in addition to the opaque data type, there are, of course, a bunch of functions, a bunch of operations on CFStrings. First of all, there are many ways to create a CFString. You can create them from a Pascal string, from a C string. You can create them from an array of bytes and an encoding. You can also create them from other data, if you will, like ints and what have you, using formatting functionality similar to the C language's printf function.

There are also several ways to extract the characters of a string and do encoding conversions, for example, on byte data, converting them to and from strings. This is very handy when you're getting information off the internet, for example, and need to convert that WinLatin1 HTML page into something you can more directly use. There are also many other common and useful operations. I give two examples here of appending and concatenation and finding type operations.

In addition to CFString, CoreFoundation provides a number of other basic data type abstractions, and here are some of them, not all of them. These are sometimes just simple wrapper objects for simple data types. For example, CFBoolean represents either true or false, and that's very straightforward. But most of the time, these data structures also provide other useful operations.

As an example, there are a few types to represent dates and times provided by CoreFoundation, and there are also some operations to work with the Gregorian calendar representation of dates, you know, years, months, days, hours, etc. These functions can do things like figure out what day of the week it is, or what day of the week it's the day of the week. what the date will be, say, 90 days from now.

And those are just representative examples of some of the functionality. Now, some of these types may seem to be really too simple to be useful API, but they sometimes come in handy when dealing with collections. And as we'll see in a bit, many of these are central pieces of the property list mechanism in CoreFoundation.

But for now, I'm going to talk about the collection data structures in CF, CoreFoundation. A collection is something that groups together other objects, and it generally does not matter what the type of those other objects is. In the case of the CoreFoundation collections, it is most convenient to store other CoreFoundation objects.

However, the operations of the collections with respect to the type of data that they can hold can be configured with callback functions to hold any pointer-sized values. For example, you can configure a collection to hold integers. The callback functions determine what happens when custom values are added and removed, and how they are compared when comparison-type operations are applied to a collection.

The usefulness of these collections is that they can manage the memory for you, and I'm going to begin by talking about two of the collections, CFArray and CFDictionary. First we have the CFArray. Like an array in the C language, the values are kept in order and are retrieved out of a CFArray using a zero-based integer index. The diagram on the right is showing this mapping from indices to values.

Unlike a CFArray, though, the values are kept compact in that if you remove an element from the middle of an array, the values with higher indices are shifted down one in order to keep the, what you might call the index space, the indices that you would use to access elements, keep those contiguous. In addition to using a CFArray like an array, it is quite common to use them as stacks and queues.

The other collection I'm going to review today is CFDictionary. With a CFArray, the pointer-sized values were indexed by integer. In a CFDictionary, the values are indexed by keys, and you can see this in the diagram, which are themselves often other CoreFoundation objects, but can be any pointer-sized values. In the diagram, the strings are being used as the keys. If I asked for the value with the name key, for example, at the top there, the dictionary would return me value 1.

A CFDictionary is somewhat like a struct in C, although you don't want to go and change all your structures in your C code to use CFDictionary's. There's a time and a place for CFDictionary's and for structs. Also, unlike a CFArray, the values in the dictionary are not kept in any particular order, and this is because CFDictionary is based on hashing for fast access performance to the elements.

And again, to reiterate, one of the principal values of these collections is that they take care of the memory storage and algorithms for you. CFDictionary and CFArray are both heavily used in the frameworks and applications of Mac OS X. And though it might surprise you, CFDictionary actually tends to be more popular than CFArray. Dictionary just turns out to be a very convenient way to structure data inside of an application.

One of the ways in which CoreFoundation uses these basic data types and collections together is in property lists. A property list is a group of CF objects of these types: CFString, CFData, CFNumber, CFBoolean, CFDate, CFArray, and CFDictionary, and only objects of those seven types. An additional restriction is that keys of a dictionary in a property list must be CFStrings, that any dictionary within a property list. So any object or group of objects which satisfies these constraints is a property list.

For example, a single CFString is a property list. A single CFNumber is a property list. But more often, a property list is a collection or collection of collections. For example, you might have an array with dictionaries in it, and the dictionaries may have dictionaries inside them, and they have keys and values, which are numbers and booleans and so on.

The special thing about property lists, this group of objects, special type of group, is that there is a persistent, sometimes called flattened representation, which is an XML-based representation. So if you have a property list in memory, you can easily flatten it and write it to a file, for example, or send it to another application.

Later, you can, for example, if you've written it to a file, read the file back in and reproduce the original object graph by using CoreFoundation to decode the XML representation back into the original objects. A file which contains a flattened property list is itself often referred to as a property list, and so the term is used for both on-disk representations of property lists, and the in-memory representation of the actual objects in use.

Property lists are used extensively in Mac OS X as configuration files and for storage of preferences and similar things. For example, applications in Mac OS X are bundles, which are represented by CFBundle, and inside of a bundle is a property list, which is the configuration information for that CFBundle, for that application. We'll be discussing CFBundle later in this talk. I'm not going to go into it more right now.

Property lists are also often simply a useful way of modeling information in an application. For example, a property list could describe a print job, and a print server might keep a CFArray as a queue of print jobs that need to be serviced. Here we have just a few of the property lists of a fictitious print job. This is not taken from any actual use on Mac OS X. Note that all of the keys in the dictionary are strings.

The keys are on the left, but the values over on the right are a mixture of strings and dates and booleans and numbers. The dictionary could also contain values which are arrays or other dictionaries, but for space reasons, we haven't shown that in this diagram. OK. Let me get that.

Now that you've seen some examples of what CoreFoundation contains, let's talk about some of the overriding philosophies, concepts, and conventions used in CoreFoundation. These are the keys to understanding CoreFoundation really, because once you understand these, you understand the basic operation of all CoreFoundation APIs. Often higher-level APIs, which are based upon CoreFoundation, have also adopted these conventions.

Picking up a new bit of CoreFoundation APIs or those higher-level APIs which use the same conventions is thus much simpler, and you only have to really concentrate on what those specific APIs do, what their specific behaviors are, and not You have to worry about figuring out what the memory management conventions are, for example, for those APIs. In particular, it is important to understand the memory management strategy and conventions of CoreFoundation, because without that understanding, you really cannot make proper use of CoreFoundation.

The general philosophy behind CoreFoundation was to create a high-performance general utility API that could be used as a substrate, that is an underlying layer, beneath both Carbon and Cocoa. We took many concepts that were already in Cocoa and recast them down into a C API, which could have wider utility. More people could make use of it. And at the same time, we extended them with some additional features.

The most important aspect to the design was that the CoreFoundation API should be consistent. An API with a high degree of consistency feels like a more unified and cohesive API than one without consistency, and it is much simpler to use a cohesive API, much more natural, and much more efficient. The coreFoundation API is a very simple and easy-to-use API.

We also decided to design the API around object-oriented models. This gave us a way to logically structure the API and a means to more easily separate interface from implementation. For example, nearly all data types in CoreFoundation are opaque, and you don't know how they are implemented. This also allows Apple to make improvements in the implementation over time without being constrained by open data structures. However, it also means that all CoreFoundation objects are essentially going to be allocated off the heap.

In part to achieve the goal of high performance API, we decided to limit the types of validation and checking that the API does, limit those to runtime errors. Thus, there's very little checking of programming errors like passing in wrong parameters. In the production version of the library, Which is the one normally that users are running against.

We don't have a lot of these, any programming error type checks. We put these instead in the debug version of the library, which uses assertions and other checks to look for these sorts of programming errors like passing in a bad type of object or what have you. One of the ways to run against the debug version of the library is explained in the CoreFoundation release notes on the system.

To ensure consistency, we adopted several naming and argument conventions. A few of them are listed here, not all of them, certainly. The abstract data types and most higher-level functionality is grouped into classes or modules, like in many object-oriented or modular languages. We've seen several examples already, like CFString and CFNumber. The type of an instance of such a class is named with the class name plus the term ref, and that is an opaque reference to an object of that class.

The operations on that type are functions, then, that begin with the class name, just as the type does, and then name the operation. So, in this example on the slide, we have CFString, which is the name of the class, appendFormat, which is the name of the operation. Another example would be CFArray.getCount, which would return the number of elements, the number of values in the CFArray at the time you called that function.

Also, in this object-oriented way, the first argument to these operations is always the object which is to be operated upon. So, for example, in CFStringAppend format, you know that the first argument is going to be a CFString. The exception, of course, is functions which create new objects. We call these create functions. Obviously, in that case, there's no object for them to operate upon. They're creating a new object.

Two other object-oriented concepts we adopted in CoreFoundation to limited extents, because of course we're operating in the C language, which is not naturally object-oriented, are polymorphism and introspection. A polymorphic function is one which can operate on many different types of values. In CoreFoundation we have eight functions which can accept references to any type of CF object. as their parameters. And of course, in some cases, they also return CF types, which are CF objects.

These are used to provide general functionality across all of the core foundation types. Let's see. As an example, to find out what type an object is, you would use the function cfgettypeid, the introspection function there in the middle, cfgettypeid, and pass it as an argument a cfobject, or what you believe to be a cfobject. You would compare its return value. It returns a type code. You would compare that return value with the type codes published by every core foundation type in its API.

So, as I said earlier, one of the most important things to understand about CoreFoundation is its memory management strategy. Reference counting is used on all CoreFoundation objects. For those of you who don't know what that means, In short, reference counting means that each object keeps track of the number of owners that it has. That's one way to think about it, at least. When the number of owners of an object is zero, the object can be destroyed.

An object may have many different logical owners in different parts of an application, and generally they don't know about one another, so reference counting is a way to make sure that an object does not get destroyed while it is still in use, before it is no longer useful.

So, CFRetain, which is one of the polymorphic functions, is used to what we call take a reference, or increment the reference count of a CF object. This is sometimes called having a retain on the object as well, because CFRetain is used to increment the reference count. The function CFRelease is used to give up your part ownership in an object. CoreFoundation's objects automatically destroy themselves when their reference count drops to zero. You don't need to do that. But you do need to get rid of any references that you do have, and I'll be talking about that.

If you have a variable which is referencing a CoreFoundation object but no retain on the object, it could be destroyed out from under you at any time, and there is really no way to find out that this has happened. That's called a dangling reference, and dangling references, just as in Mac OS 9 or any other system, can cause app misbehavior or a crash.

[Transcript missing]

CFRetain is used to explicitly take reference, but sometimes a retain is automatically given to you when you get an object, say, as a return value. These automatic retains, in addition to the ones you explicitly do with CFRetain, must be released later when you no longer need the object. If you don't do that, the memory is not going to be freed, and you're going to have a leak, which will cause your app to use more memory than it needs to.

So you have to know when you need to explicitly make yourself an owner of an object, and know when you have been given an ownership in an object. And this is a fundamental question that arises for a developer. How do I own this particular object? To answer that question, we develop conventions for CoreFoundation. As our example, we're going to look at the naming convention for functions which return CoreFoundation objects, as that is by far the most significant convention.

By convention in CoreFoundation, if a function returns an object of a CoreFoundation type, it uses the verb "get" if it is returning the object to you, but not giving a retain on that object to you as well. That is, it is not automatically returning a part ownership in that object to you. For example, CFDictionary get value would return the value out of a CFDictionary, but would not give you a retain, increment the reference count automatically on that object. And you should not release values which are returned from get functions, or you will create a dangling reference.

Functions which automatically do retain a returned object for you use either the verbs copy or create, depending on what the function's doing. Functions which create new instances use create, for example. The objects you receive by calling a create or copy function must have that retain released by you when you are done with that object, or you're going to have a leak. This is so important it really deserves repeating. Get functions never automatically increment the reference count. Create functions and copy functions always increment the reference count of objects that they are returning.

So these conventions are for the programmer's benefit. They're easy to remember, and they're ways for you to know automatically when you see an API what is happening with respect to the memory management of that returned object. The use of copy and create as verbs should not be taken to mean that objects are always being copied or created. A copy or a new object would not be created when it's not appropriate. For example, sometimes it's done for efficiency. Another example would be a type which kept a cache of all the objects, for example, that it had created because it was uniquing them in some way.

Create function might return an object out of the cache rather than making a new one. But the reference count on that returned object is always incremented, whether it's a cached object or a new one. Well, and by the way, such a cache would probably be implemented, often be implemented, by using a CFDictionary, as I discussed earlier.

Okay, there's one final general facility that I'm going to discuss before we move on to talking about some of the higher-level application services in CoreFoundation. That's what we call toll-free bridging. This is mostly a benefit for Cocoa applications and frameworks, but it also helps a lot in a mixed Cocoa and Carbon environment.

Some of the basic data types in CoreFoundation are bridged to their Cocoa counterparts such that the CoreFoundation type and the Cocoa type are interchangeable. As the example at the bottom shows, a simple cast is all that's needed to convert the Cocoa NSString to a CoreFoundation CFStringRef, and vice versa, to convert a CFString to a Cocoa NSString. This allows these CoreFoundation and Cocoa objects to be easily shared and passed around the different layers in the MACWIS10 architecture. The list of CoreFoundation bridge types is in the Foundation release notes on the system. I haven't listed them here.

Okay, now I'd like to introduce Doug Davidson, who will take us through some of the application services available from CoreFoundation. Doug? Thanks, Chris. So, first I'm going to talk briefly about some basic application services available on both Mac OS 9 and Mac OS X that probably most applications are going to want to use. And then I'm going to go into a little more depth on some advanced application services that CoreFoundation provides on Mac OS X.

So let's start with the basic application services, CFBundle, CFPlugin, CFPreferences.

[Transcript missing]

CFBundle is the heart of our localization strategy. This is what allows us to ship Mac OS X simultaneously in many different languages. Because what CFBundle will do is automatically provide you with the correctly localized version of any particular resource based on the user's preferences.

CFBundle also has some basic code loading facilities. That is, it can load code and allow you to look up symbols within it. And in particular, it can do this transparently whether the code you're loading and whether the code that is doing the loading is Maco or CFM on Mac OS X. Some of you have probably already used this facility, for example, to allow CFM executables on Mac OS X to use functionalities from Maco frameworks.

Now, the functionality that CFBundle provides is enough for basic loading of plug-ins. That is, you can load it and you can look up entry points within it. But what it doesn't do is manage the interface between the host and the plug-in for you. For that, we have a specialized kind of CFBundle called CFPlugin.

Now, it's possible you may already have an interface between host and plug-in that you use, and in that case, you might not be interested in CFPlugin. But if you're looking for such a thing, you might want to consider CFPlugin. I'm not going to explain in detail how it works now. It works, the host looks up interfaces by UUIDs, where the interfaces are C++ or COM style tables of function pointers, and those get passed back.

The best place to learn about this is through some examples that we have, both in the CoreFoundation documentation on Mac OS X and in the CarbonLib SDK. You'll also find that there are a few places on the system where... We use CFPlugin as our interface for plug-ins, for example, for plug-ins for the printing subsystem on Mac OS X.

And finally, CFPreferences. This is our general facility for small, flexible application preference storage. And these preferences are usually both per user and per application, although there are other possibilities. And the way this works is that any particular preference is referred to by a name, which is just a CFString key.

And the value of the preference can be any property list type, so it's very flexible. All you do to store a preference is just set that preference for the name key, the name, and you just look it up by name when you want it. And CFPreferences takes care of everything else, handles all the storage for you. Currently, they're stored using the flattened XML representation for property lists.

There are a couple of caveats. This is not intended for huge caches or large chunks of binary data or anything like that. Also, you need to be sure that anything your application absolutely relies on is not stored here. These are stored external to the application, and it's possible that users could erase their preferences.

You should be prepared for the possibility that preferences are missing or corrupted for some reason. But it is a very valuable general facility. We use it all over the place. Many of our system preferences are stored in this way. For example, the user's language preferences that I mentioned in the case of CFBundle are stored using CFPreferences.

Okay, next I want to go on to some advanced application services in Mac OS X, starting with CFRunLoop, which is the basis for the rest of these, and then I'll discuss some things that are enabled by CFRunLoop. So the RunLoop. What is a RunLoop? Carbon event-based applications and Cocoa applications have something in common. That is, they're both fundamentally event-driven. The way they work is, events come in, they're passed to the application to be handled, then controls return and you wait for something else to happen again. The fundamental mechanism that underlies this in both cases is the RunLoop.

Now, we call it a run loop because we say that it runs and that it loops, but mainly what it does is it waits. It waits for something interesting to happen, tells you about it, you handle it, and it goes back and waits again. And the thing it waits for can be any of a wide variety of things.

It might be the arrival of a Mach message, it might be perhaps the arrival of a network packet, it might be just the arrival of some specific time. But the important thing about the RunLoop is that it can wait for all of these things, a wide variety of things simultaneously, efficiently, easily, without pulling, without using processor resources. This turns out to be a very powerful concept.

Now, each thread has exactly one RunLoop object. There may be many interfaces to it, so CoreFoundation, through Carbon, through Cocoa, they're all dealing with the same underlying object. You can use any or all of them. Typically, you would want to use the highest level interface that suits your purposes. Often you'll be using it through Carbon or Cocoa, but if you happen to be using a CoreFoundation level source, something at the CoreFoundation level that the RunLoop can wait for, then you would want to use the CoreFoundation interface to it, which is CFRunLoop.

Now, one thing about RunLoops is that you may not want to wait for any possible type of event source at any given time. For example, you might not want a certain timer to fire while you are tracking mouse moves or something like that. So RunLoops have something called modes, and at any given time, the RunLoop is running in a specific mode, and any particular source is registered with the RunLoop for only a certain set of modes.

So, for example, in Cocoa, there are a couple of specific defined modes that Cocoa uses. One, the modal panel RunLoop mode is used when the modal panel is up and is waiting on that. There's another one that's used typically when the mouse is being tracked. But normally, the RunLoop would be used and run in the default mode.

And when you register a source with the RunLoop, you can register it with a specific mode or set of modes, or you can choose to register with the so-called common modes, which is a set of modes determined by your application environment. In Cocoa, it would be the default mode plus the modal panel and event tracking modes.

Now, the RunLoop by itself is not terribly interesting. What's interesting are the things that it enables, the things you can do with it. So, at the CoreFoundation level, some of the things that can wait for are, well, first of all, you can use it to wait for raw Mach messages or raw network packets.

And if you want to do that, we have a CFMockPort for waiting for raw Mach messages or CFSocket for waiting for events on a socket. That's useful, for example, if you're in a Carbon or Cocoa application and you want to wait for these things. You don't have to spawn a separate thread to do that. You can simply be notified. You can get a function callback within your main event loop.

And I'm going to go into some other CFRunLoop sources in just a moment. You can create your own. It is a little tricky to do so. So another thing I said you could wait for is just the arrival of a specific time. And you can wait for a single time or a repeating sequence of times with a CFRunLoop timer.

What you do is you create the timer, tell it what time or times to wait for, and you tell it what function will be called back when that time arrives. And then you attach it to a run loop in a given mode or set of modes. And when the run loop is waiting in one of those modes, it checks to see if your time has arrived.

And if your time has arrived, then you get a callback. Now, if you're waiting for a single time, then the timer is automatically invalidated after that time has arrived and the timer is fired. If you're waiting for a repeating sequence of times, then you would have to invalidate the timer yourself when you're done with it.

Now, I talked about raw Mach messages. They have a lot of advantages. They're the fundamental low-level local IPC mechanism in Mac OS X, and they're very powerful and high performance, and they have a lot of flexibility, but they can be difficult and tricky to use. So we also have a slightly, just one higher level, one level up mechanism built on top of them in CoreFoundation called CFMessagePort, which is a high performance, low overhead local IPC mechanism. And you can use it either asynchronously, sending messages one way, or synchronously, sending a message and getting a reply.

The way you use CFMessagePort is that you create a local message port on one end, and And these built ports can be advertised to other processes on the system with a name, which again is just a CFString. And you create a remote message port looked up by name to represent the other end, the end to which you're sending.

The message that you send is just a CFData, that is a collection of bytes, plus optionally a message ID, an integer. And the reply, if you want to get a reply back, is a CFData. So what the intended receiver of the message will do is to publish as API the protocol for this message. That is, how to interpret the data, or the message ID of both, and whether there will be a reply and how that should be interpreted.

The sender would create a remote message port to represent the port, the destination of the message, and call CFMessagePort send request with the message to be sent. Then the receiver will be notified within its RunLoop getting a callback, and if there's a reply, the receiver would return the reply, and then the sender would get the reply, and the message port send would return.

Now, there's also another mechanism that we have built on top of these, which is perhaps lesser known, but very useful. And this is a broadcast local IPC mechanism, CFNotificationCenter. And what this allows you to do is to post happenings of any sort to an arbitrary, possibly unknown, set of receivers.

These notifications are identified by their name and optionally also by another string. The name, again, is just a CFString. Optionally also by another string representing the object that sends them. And they can carry with them essentially arbitrary data, again, a property list. In this case, the sender would specify what sort of notifications it's going to send out, what their names would be, and what sort of information they would carry with them. And when the sender wants to send one of these notifications, it simply posts it and goes on its way. It may choose whether the notifications are going to be delivered immediately or not.

The receivers, if anyone on the system who wants to receive such a notification simply registers to receive it. The sender doesn't have to know anything about them. You register based on the name, optionally also the string representing the sender. And you can choose whether you want to receive these notifications immediately or whether you want them to be delayed.

Because typically, it's not necessary for all the receivers to get the notification at once, and it's rather expensive to wake them all up, wake up all these processes at once to deliver the notification. Often, it's enough if you will simply get this notification the next time you become active. And if you, a notification might be sent multiple times, you can choose to have those coalesced if you like.

So this is a very useful mechanism. It's not intended for large amounts of data or very high volume or frequency. But it's useful in a variety of circumstances, especially, for example, in combination with other channels of information. For example, if you had a suite of applications on the system that all shared a set of preferences, and one application was going to change those preferences, it could send out a notification to let all the other applications in the suite know that the preferences have changed, and then at their convenience, they could look up the changed value. Or if you had some area on the file system that you were working with, and you changed it, you could send out a notification to let any interested party know that it had changed, and that they should go and look it up and see what had happened.

So now, let's discuss where you can go for more information about CoreFoundation. There is documentation on your system and online. There are a number of examples, both with your Mac OS X Developer CD and in the CarbonLib SDKs. And you should not forget to look at the release notes, which describe anything new or anything that has changed in CoreFoundation.

And there are some specialized release notes that are more like discussions of topics in depth, one on CFBundle and CFPlugin with some detailed examples of CFPlugin, one describing the info dictionary in a bundle in detail, and one on localization. And now I'd like to bring Mark Turner back to wrap things up and start our Q&A.

Let's take a quick look at, well, I was going to say what the roadmap is, but let's talk about this. So yeah, as I said, I'm the Carbon Technology Manager. Although CoreFoundation is obviously not a carbon-specific technology, I'll be happy to take your questions or comments about CoreFoundation. You can email me at [email protected]. There is the email address here, which is read by the engineering team, so that's another great place to send your feedback.

And these two mailing lists I encourage you to get on if you're not already. It's a great place to get your questions answered and share your knowledge about Carbon, Cocoa, and CoreFoundation. These lists are available if you haven't been there before. There's a webpage at lists.apple.com where you can sign up for a great many Apple mailing lists.

And now, so here we are, 10 o'clock Friday morning. Most of these sessions have gone by already, but I'd like to highlight them for you so that you can look at them on ADC TV or on the DVDs when you get them. First being the Cocoa Overview. That's a great session just for those of you who haven't gotten started yet with Cocoa. The Carbon Event Manager is another overview session for Carbon developers. We really encourage you to look into the Carbon Event Manager. It simplifies your code and gets you much better performance on Mac OS X.

And then the advanced Cocoa Topics session, which we had yesterday, for more information about the RunLoop and other things that Doug mentioned. And if you're here this afternoon, the Cocoa Feedback Forum would be a great place to bring your questions about Cocoa and, of course, CoreFoundation because many of the same people will be there.