Leopard Innovations • 58:10
The Address Book framework leverages the Mac OS X contacts database to provide access to a user's contacts in your application. Hear Apple engineers explain the architectural improvements to Address Book in Mac OS X Leopard and learn how to interact with contact information or present Address Book components in your user interface.
Speakers: Brendan Langoulant, Joe Engel, Brett Neely, Colter Reed
Unlisted on Apple Developer site
Transcript
This transcript has potential transcription errors. We are working on an improved version.
My name is Brendan Langoulant, and I am an engineering manager for Address Book and Mail. Today we are here to help you ensure that your customers' important contact information isn't isolated from the Apple ecosystem. And we're going to take you through three major sections. The first section is really going be about how to -- giving you an understanding of the layers involved and building up from some of the basics of how to use the API. Going through some of the data types in the core functions that you need to know in order to development an application using Address Book.
Then we're going to move on to giving you some examples of how to use some of these interface elements that we provide you. And actually add a hook into the Address Book application that you might be able to find ways to -- find new ways to integrate your application with the Address Book application.
And then finally, we're going to move on to how to make sure that you're using the best practices. We've made some changes under the hood with your Address Book. And we want to make sure that you're really not wasting time taking the wrong approach, that you're actually using the best practices that we suggest. And making sure that you get the best performance.
So in the dark days of Macintosh we had many, many different contact management databases. That meant that each developer had to implement their own contact database. It meant that customers, worse had to actually go and implement or type in the same contact details over and over again. And that was not very good. So we really didn't -- we thought maybe there's a better way of doing this.
Hint; born, the Address Book framework. So as you can see up here, the Address Book framework is used by a lot of applications. Here are some of the applications. Going through applications like mail, which uses it for e-mail addresses. Applications, iChat for doing IM handles. Interesting one. ICal, using it for birthdays and for attendees, when you're actually inviting people to your meetings.
And there's a lot of other applications. In fact when we're going through of the process of making Address Book 64-bit, we really understood how many applications inside Apple used the Address Book framework. There's a large hierarchy of applications which are all based on having an Address Book somewhere. Here's some applications that are already using the Address Book framework. And they're already getting the benefits of using a centralized database for managing their contacts.
So some of the benefits that you get by using this database -- as we add more devices to the Apple ecosystem, your contact information will automatically migrate into those devices. So when we first developed Address Book, things like Sync didn't exist. So when we added sync, that meant that automatically your contact information went to places like dot Mac, to iPod, and other devices that you might think of.
One of the new things that we've done in Address Book is add Time Machine support. So what this enables your customers to do is if they realize that they've either changed a piece of data on a customer, or one of their contacts, I should say, and they no longer can find that information, you can launch into Time Machine, type in the name of that person, and then fly back through time to find that person and retrieve those contact details. Worse, if you happened to have deleted the person, then you can also go back and retrieve it in the same way. So in effect, your customers automatically gain this benefit by using -- your customers will gain this benefit.
One of the things that we've done under the hood for Address Book is we've replaced our own database with the CoreData database. And we've done this for a couple of reasons. More of which we'll get to later. But some of the reasons in fact were to help us support some of the Time Machine. Also to make sure that we don't use too much memory when managing the contacts.
And really to make sure that the on disc representation of those contacts remains coherent. So really, no matter what happens, you know, ecstatic shot, cosmic rays, that your data is really safe from any problems. Or unexpected problems, even worse. So with that, I will hand over to Joe who will take you through some of the overview and give you an understanding of the API.
( Applause )
Thanks Brendan. My name's Joe Engel. I am a software engineer in Apple's internet technologies group on Address Book. And this is my slide. Today, I'd like to help you learn how you can integrate your applications with Apple's standard system repository for contact information by going over an overview of our most commonly used APIs and tasks, as well as some of the architecture involved.
So onto the architecture. This is by now a possibly familiar looking stack diagram of the Mac OS X operating system. And at its core is the Darwin foundation layer. Which is where the kernel and V F S and concrete file system implementations reside. And as Brendan mentioned, now that we're using CoreData this offers a robust backing store, which offers type integration with each of these file system implementations to provide for file amnesty, and coherency for all of your database transactions such that even in the event of a power failure the database integrity should be maintained.
Additionally, this is where the I O sub systems and networking stack reside. And these are leveraged by the sync services layer in system services. To allow all of the information your applications enter into the Address Book a conduit to devices like iPod, PDAs, cell phones, as well as network services like dot Mac, so your data can be universally available. Also at this layer is the notification server. And Address Book makes use of notifications to notify your application when another application on the system has made a change to the underlying data store.
And this allows every application to maintain a synchronis view of all of the information. So when I user adds a contact or removes a contact from the Address Book application or when your application updates a record or adds a contact. Every other app can see it as well. On top of this is the frameworks layer, where Address Book itself resides, as a peer to framework such as Carbon and Cocoa.
Here we provide Objective-C interfaces for foundation and Cocoa applications as well as C interfaces. Which can be used by Core foundation applications and B S C applications, as well as Carbon apps. We won't be discussing the C interfaces very much today, although the Objective-C interfaces and the C interfaces have future parity, and I think you will find them to be very similar. So a transition between the two should be fairly natural.
On top of the frameworks we have search. Now search has been an increasingly important technology in Mac OS X. In 10.4 Tiger, we did Spotlight, which began to offer users content indexing of all the meta data stored in the Address Book records. So Spotlight defines property types for each of the pieces of data in a record Such as the e-mail addresses and phone numbers. And using the Spotlight APIs, or the Spotlight feature for the interface, your users can quickly search this information and your applications can retrieve it.
Inside of the framework we also have a class called A B search element. And you can use this to formulate expressive queries about those data that you wish to retrieve from the persistent store. And this is increasingly important in Leopard for performance reasons, which Colter will be getting into later. But this is also a handy way to retrieve just those contacts that you wish.
And on top of all this, we have the user interface layer. And this kind of falls into two categories for Address Book. The one most people are familiar with as users is the Address Book application. But as developers we provide a hook for you to provide an action associated with any bit of information so that you can link the Address Book application into your app. So when you roll over one of the properties, a plug-in that you write can invoke your application to perform whatever application may be appropriate.
Additionally, we provide a user interface module which reassembles the UI inside of the Address Book application. And there is a pallet available in interface builder. So you can just drag this out into your application and use it. And it's customizable, so that it can show only that data which you're interested in for your app. Of the pallets available in Tiger. And unfortunately it didn't quite make it into the Leopard DVD that you have this week. But I think we will be addressing that shortly.
So when you actually want to go and use the Address Book, the first class that you're probably going to need to interface with is AB Address Book provides a work space into the world of Address Book. It internally manages interactions with the Address Book persistent data store as well as providing a conduit for search and localization internally.
So in order to get an Address Book object, you can use the shared Address Book method on AB Address Book. Every invocation in your application will return the same object. It's a single ten or shared object. There's also a new method called Address Book, which will turn a unique object, which Colter will be discussing.
Once you have this object you can query the set of all people in the database using the people method, which will return array of people, or groups, which will return an array of those groups that have been defined either by your application or by the users using the Address Book app.
You can also manipulate the records with AB Address Book through of the simple methods, add record, remove record, and when you're done making these changes you can commit them to disc by calling save. So what are you getting back when you call people in groups. And what are these AB records? Well, you're getting back an array of AB records for people in groups. And the AB records themselves are an abstract superclass for all data types with an Address Book. And presently this includes people, which are also companies, and groups, which are containers for other AB records.
There are a number of methods that are available on all AB groups. And you may notice that this reassembles a map or a dictionary in that we have a number of predefined property constants for all Address Book types. So at the AB record level, there are some defined.
As well as some that are only valid for the scope of AB person and AB group. Using value for property, if you pass in the associated prompt con constant for a type, for example, it would be first name. You will be returned an NF string for a first name for AB person.
You can manipulate the record using set value for property. And when you wish to remove it using remove value properties. Fairly straight forward. One important bit about AB record is that when you're integrating your application with Address Book you'll probably want to maintain some sort of correlation between your data types or your records and Address Book records.
And the appropriate way to do this is using the unique I.D. method. This is available on all AB records, and it will return an N F string which uniquely identifies this record in the database. All other pieces of data in the record are mutable. Such as the name may change, or any other piece of information. So if you want to keep a consistent reference to this you should use the unique I.D. method and store that in your application.
Here's some examples of some of the properties available on AB record for different types of record types. So on the top we see that we have the KAB last name property -- and this returns -- not surprisingly, the last name or surname of the individual represented by the AB record. The KAB birthday property, however, will return an NS date. There's some properties which are only valid for groups. Such as the group name property, which returns the string of the group name.
And then there are a few that are available on all records. And these include the creation date property. Which is a date as well as modification date property. And NS date as well. Now there's one item on here as a data type that you may not have seen before which is the AB multivalue class.
So what does this do? AB multivalue is used for those situations where you may have data that has multiple roles. For example, telephone numbers. You have a home number, a work number, and also possibly a mobile number. And rather than having a single attribute for this, AB multivalue allows you to keep track of these on a pro role basis. The multivalue has sub elements, and to find the number of elements in it, you can use the count method.
Up until Leopard you had to access these by index. And the traditional ways of doing this are evaluated index, label index, and identifier index. Up to the count. So there are three properties associated with each element in an AB multivalue. So there's the value itself. And there's the label.
Which is an identifier for the role. But the third one is the identifier itself. Which is a string similar to the unique I.D., which uniquely identifies an element inside of the AB multivalue. So again, if you want to maintain a reference to a particular data inside of AB multivalue you should do so using the identifier.
Because the label may change as well. Perhaps the land line's been converted to a mobile number, or the number's changed. But if you want to keep a reference to just that element, use the identifier. Excuse me. And new in Leopard we have two new method which are convenient with Objective-C 2.0's class denumeration feature.
And these are value for identifier and label for identifier. Which allow you to bypass the indices entirely. So you can enumerate over the identifiers in a four-loop and access just the values and labels. There's another variant of AB multivalue. AB multivalue itself is immutable. However, there's also a mutable variant for mutable multivalues that you can change and then store back into the database.
The second type of record that I mentioned is AB group. And AB group serves as a container for other AB record types. Now being an AB record type itself, this means that AB group it contain other AB groups. And you can do this on the Address Book application very easily by dragging AB group into another. And this is handy for, like, scenarios like Brendan, who manages as he said both mail and Address Book. He might have one group for all the Address Book engineers, one group for all the mail engineers.
But when he wants to send mail to his entire organization, he could have a group that contains both of those groups. And here's where hierarchy becomes very useful for your users. You can query the membership of a group by calling members, which will return an array of AB people, or AB person objects. And add member and remove member may be used to manipulated the list.
For examining the hierarchy, you can use parent groups. To find those groups that are contained by this group and other groups to find those groups that this group contains. There's one additional feature in AB group which is a kind of hidden feature. But it's been around. And that is distribution lists.
So for multivalues you may have several e-mail addresses. You might have a work e-mail address, a home e-mail address for the e-mail property. But when you send e-mail to a group, how do you know which e-mail address it's going to pick. Or more importantly, how do you specify which one? If you're sending a work-related e-mail you probably want it to go to their e-mail address at work.
And you can use a primary identifier on the group using set distribution identifier for property person. You just pass the identifier for the element in the AB multivalue that you want to associate as the primary one for this group. Pass in the property string for the time, and then the person that you want it to be applied to. And one final bit. Into the bit passed into the API level, but still quite important is that of the notifications.
Address Book using notifications to alert your application about database state changes. So if you're running, and another application is running, which is almost guaranteed to be the case, many of these apps may be making changes underneath of your app. So if they're running your application and they're also running the Address Book application, they could be making changes to contacts, or possibly even deleting the one you're working with.
These notifications allow you to respond appropriately to these actions. And it's especially important that you not continue to reference deleted records. If you have any sort of interactive use of the API. It's not quite as bad as, say, referencing deal indicated memory. It won't cause a crash in your application, but it will raise an exception because underneath of the framework it causes a fault that CoreData could not fulfill because the record has been deleted.
So if you just listen to these notifications you will be fine. But how do you know that a record's been deleted? Well, there are two kinds of notifications. And the most important one is the K A B database changed externally notification. And this informs you of changes made by other applications to the database.
We also have a K B database change notification. And the distinction between the externally changed notification and the change notification is that the AB database change notification is only sent to you if you register for it in response to changes that you make to the database. This is mostly a convenience. So that if you have multiple windows or multiple views, your view controller are register for interest in this notification. And when one of your windows makes a change to your model then all of your views can be updated.
If you called the user info method on the notification objects sent to your notification handler. You will be sent or you will be returned a dictionary object with three keys. And these allow you to know precisely what happened under the hood. Why some other application or your own, to the database. So if you want to find out which records have been deleted, you can use the deleted records key on that dictionary to retrieve that list as well as a list for inserted records or updated records.
All of these notifications are sent by the default notification center, and not the distribution notification center. It might seem natural that because the external change notifications are coming from other applications that they would be sent on the distributed notification center. But they are all sent by the default notification center. So use the NS notification center and not the distributive notification center this is. There may be some distributive notifications underneath the hood. But the framework will interpret those and rebroadcast them to you as local notifications as appropriate.
And that about covers the API overview. So I would like to turn this over to Bret who's going to be going over action plug-ins for the Address Book application, as well as how to use the people picker. Bret?
( Applause )
I am Brett Neeley and I work on Address Book as the quality assurance and build engineer. Let's get started to these two topics. First I will be talking about the people picker, which is a user interface we provide in your framework to let users take advantage of contact information they already have in their databases. Secondly, I'll talk about the action plug-in API that we provide allowing you to add features to the application and hook into services or applications that you provide.
So why would you want to use something like of the People Picker in your software? Well, let's take a look back at the early days of commerce on the Web. Have you seen something like this before? This is a site where maybe you're making a purchase here, and the site is asking you to enter your billing and shipping address.
Well, because of the way this form is constructed you have to enter that information twice. Isn't that a hassle? So move beyond this interface, and to improve it is to add a check box here that says use the same address for billing and shipping. So now you can only enter the address once. And that's nice.
But if the address is already on your system, why not just take advantage of that data and not retype anything at all. And if that's what you want to do then you should use is People Picker. What does the People Picker look like? Well, let's start by taking a look at the Address Book application.
This layout has three columns in it. Groups are on the left. Names in the middle. And then values on the right. And at the top right of this window you'll see our search field. So now I'll show you the People Picker. And this layout pretty much matches the Address Book application. Groups on the left. Names in the middle. Values on the right. And the top right of this window also has a search field.
Let's take a closer look now at how the mail application uses the People Picker. This is mail's People Picker, and I'll point out two things here. First, on the right-most column the mail application configures the People Picker to display e-mail addresses. For e-mail application, the e-mail property in AB person is the most important type of value to display.
Now second, on the top left of this window we see these three buttons. Well, how did mail put these buttons into our user interface? Well, this is actually public API. This is called the accessory view inside of the AB People Picker view that we provide for Objective-C developers.
So using these three buttons, mail is able to provide a complete work flow for composing a new mail message to an existing e-mail address into the Address Book database. So when the user selects an e-mail address, presses either 2 C C, or C C B here, then that e-mail address is added to a mail compose window. Now let's look at iChat's People Picker. This is a little bit different. And I'll point out a couple things here as well. First you'll notice that the right-most column is displaying the Aim property from the AB person class.
This gives the user the opportunity to add buddies to their Aim buddy list by using a value from their Address Book. If it exists there already. But you also notice that next to the Aim column in the column header is the up down arrows. And this indicates that the People Picker is providing you with a pop up menu.
So the People Picker can provide more than one prompt, but not more than one at a time. So the iChat People Picker shows both the Aim and the e-mail properties. Now why does iChat need to use the e-mail property in addition to Aim? Well, this is because dot Mac e-mail accounts can also be used as Aim buddy handles. So if you have an Aim account, or a Mac dot com e-mail address in one of your existing contacts, you can select it from this UI and add it to your Aim buddy list.
Now iChat also puts these three text fields above the People Picker. And what do these do? Well, it seems to be just showing the same information that's displayed with the current selection in the People Picker. But these are also editable text fields. So say that you select a contact in Address Book that does not vet have an Aim account associated with it.
You can select that contact, go to the account name text field above the window, above the People Picker view, and then type in the account name and press the add button. And that will do two things. That will save the Aim account to the Address Book card and the Address Book application and then add the Aim account to your buddy list as well. So iChat is providing a complete work flow within this window to add existing or new Aim accounts to your buddy list and up date your Address Book application if necessary.
And you don't have to jump back and forth between Address Book and iChat to accomplish this. Now how is iChat keeping these text fields in sync with the selections inside the People Picker. Well, this is done with the selection change notifications that we provide in the People Picker which I will talk about shortly.
In order to retrieve values from the People Picker, you can add buttons to accessory view as I pointed out with the mail example. Or you might decide to configure double actions to associate with name or group selections. So a double action is a double-click on the user interface. So if a group or a name is double-clicked then the method that you provide will be invoked. And it's this easy using one of these two methods to retrieve the selected values or the selected records from the People Picker.
The notifications I mentioned during the iChat demo, the screen shots, the notifications are shown here. AB People Picker group did -- group selection did change notification, or name selection did change, or value selection did change. You can register for any or all of these notifications to update your user interface or take some action. And this code example at the bottom will show you how to do that. In this example we register tomorrow the AB People Picker value selection did change notification. And when that notification is received, then the picker up dated method that's highlighted here will be invoked.
Let's summarize what we've just been discussing about the People Picker. This is a familiar user interface that's based directly on the user interface of the Address Book application. It's a great way to provide an interface to your users to use information already entered in their Address Book. And to avoid the hassles of retyping something that they know they just typed in a few minutes ago, or some time in the past.
Search is provided for free in this user interface. All of the People Pickers have the search field at the top right so users can quickly filter the name list by typing in a search term there. The picker is provided for both C and Objective-C developers, and the difference between these two People Pickers is that the C People Picker is a window, whereas the Objective-C People Picker is a view. And the Objective-C People Picker also provides the accessory view, allowing you to add some user interface elements. All right. Let's move on, and now we'll talk about the Address Book plug-in APIs that we provide in the application.
So the action plug-in API allows you to add features to Address Book that hook into your application or service. How does this look in the application? Let's take a look at this Apple card here. So we see a phone under, an URL, and a street address. And on the left of these values we see what's called the label Now clicking on the label will bring up a menu of options. And let's click on the menu to the left of the street address, for example, and we'll see this pop up menu. This is what we call the option menu.
These options here are actions that can be performed on the selected value. So the first option here is Map Of. And this will map the street address in your Web browser. And new for Leopard we are mapping these street addresses with Google Maps. So what's it like to create one of these plug-ins? Well, it's not too hard at all. Let's take a look at X code. And I will be switching to the demo machine please.
Okay. So I launched X code. And I'll go to the file menu to open a new project assistant. So scrolling down to the bottom we find this group called standard Apple plug-ins. Here we provided plug-in templates for C and Objective-C developers. And I'll do my demo in Objective-C.
And we'll give this -- we'll give the project a name. And then hit finish. Here's your plug-ins project. And at this point we'll just go ahead and build it. Because this is already a fully working plug-in. Now plug-ins can be installed into one of two locations on the system. They are be installed to the top level library directory, which means that the plug-in is visible to all users. Or the plug-in can be installed into the user's directory, so it's only visible to that user.
For this example I am going to install the plug-ins for only this logged in user. So it's going to be library directory. And here's the Address Book plug-ins directory that we provide. And so this is empty right now. There is no custom plug-ins installed -- let's go find the build directory for the plug-in project that I just created. Okay. Here's session 209 plug-in. Build. Release. And here is the bundle that we just built. So now I'll just drag this into the Address Book plug-in directory. Sorry. That was so loud.
And now I launch Address Book. So this plug-in by default works with the K A B property on AB person. So that means when we bring up the phone action mean you we will see a new menu item, and it's called Speak 1-800 My Apple. And what we've done here is we've taken -- we've retrieved the value of the phone number that the user selected from the card and we used that to fill in the menu title, and I'll show you how that's done in just a moment. So let's go ahead run the plug-in now. ( Applause ) >> 1 -800 My Apple.
- Goodness, that's loud. I will do that one more time, a little bit quieter.
- 1-800 My Apple.
- Okay. That was kind of a phone number. Okay. So now we've seen how the plug-in can be installed, built, and then shown up in Address Book. Now let's take a look at the code behind the plug-in.
Our plug-in API is based around four tasks. So whether we're doing C, Objective-C, or Apple Script, you'll have to implement four methods, functions, or handlers to perform the plug-in actions. First we have this action property method. This method tells Address Book which property on AB person the plug-in will operate upon. So this is returning KAB phone property, which is one of the can constants that we provide in the framework.
Title for person identifier. Now this method retrieves -- receives two parameters from the Address Book application informing which AB person is current displayed in the application, and which unique identifies the value in the multivalue that the user has selected. And this method is responsible for setting the menu title, which is done here on the last line. So see here that the code is based around retrieving the value from the contact and then setting the menu title with Speak Value.
Perform action for person identifier receives those same parameters I just mentioned from the Address Book application. And this is responsible for actually doing the work of the plug-in. And in this case, the example that we provide is we create an NS speech synthesizer object, receive the value from the record, and then have the speech synthesizer speak the value.
And finally, should enable action for person identifier again receive those same parameters, and give you the chance to initially enable or disable your plug-in. Based on whether or not the value meets the criteria. One example of how you might use this is if you're writing a plug-in that works on the phone property and you can only operate on 1-800 numbers, or if you're operating on the KAB or URL's property, and you can only work on HTTPS URLs. If you wanted to disable your plug-in, you would return no unconditionally in this method here. And then your menu item would still appear in the user interface, but it would be disabled.
So that's all the code that's behind this plug-in that I have shown to you. I now have another example to show. To give you an idea of how else this API can be used. Let's go back to the Address Book plug-in's directory for this user. And I have a street bundle that we've created. This is from Joe.
Then I'll launch Address Book again. And okay, here's the card. So I heard there's a cool store somewhere near 1 Stocking Street here in the city. Now I have any new plug-in title here called take a look around 1 Stocking Street. Let's run that and see what it does.
Okay. This will bring up Google maps. And now we're using the street view from Google maps. So let's rotate here and see what's around here. I think I see something that I like. That looks like an Apple store. Okay. That's cool. Let's see what's down here. Just zoom in.
Ah, I see some shuffles there. Look at all those pretty colors. And note that if you're going to park here just pay that meter, because those tickets are expensive. So that's another example of what you can do with the information that you can receive from Address Book through the action plug-in API.
Okay. Now switch back to the slides please. Seed developers can use this call back based API which structured very similarly to our Objective-C API for the action plug-in interface. And you'll notice the same values, the same value parameters are passed in to you from the Address Book application. Person identifier, except these are AB person refs in C F string refs.
This is also a fully working template installed for you in X code when you use the standard Apple plug-ins group. We allow you to write plug-ins using Apple Script. Here are the four handlers that you would implement to do that. And whether you're writing a plug-in using Objective-C, C, or Apple Script all the plug-ins are installed to the same locations that I mentioned earlier.
Now I'd like to talk about some best practices for using this API. It's important that your plug-in is able to load quickly, and quickly tell Address Book what the menu title should be for the plug-in. Plug-ins are only loaded at the time the user first brings up one of the action menus in the user interface. Also keep in mind that if you're developing and shipping a plug-in, your plug-in might be only one of several that the user has installed.
Appropriate actions that you can perform with this plug-in interface is you can openly an URL to direct the user to an on line service of some form. Or you could pass the value to your own application. Either through a local URL or if the app is already running, you could post notification so send the value.
Now summarize the action plug-in APIs for you. This is a simple but powerful API that we provide to you to let you hook your features or services into the Address Book user interface directly. You would use Objective-C, C, or Apple Script to do this. And developers of C and Objective-C can use the templates that we provide in X code to get started very quickly. Once you make the template project I did of X code, you already have a fully working plug-in. So you can build it, run it, and then modify it to your needs.
And you can use this API to pass values to your application or service directory from the Address Book user interface. Not that you know all this I hope that you go forth and write some great new plug-ins for our Address Book application. Now I'll introduce Colter Reed, who will come to talk to you about the best practices with the Address Book API. Thank you.
( Applause )
Thanks, Bret. Good morning. I'm Colter. One of the Address Book engineers. And the next 15, 20 minutes I'm going to cover some best practices to keep in mind when you're developing for the Address Book framework. We made some changes behind the scenes for Leopard and we want to make sure that you're aware of a couple potential hot spots, to keep an eye out in your code.
Or if you're just developing your application, hopefully we'll get you started on the right foot. We want to make sure that the changes that we've made to Leopard will work to your advantage. We'll be covering three things. All of them have to do with performance. The first two are going to be ways that your application can use less memory and get things done faster. And the third one is going to be going into how you might be doing as little work as possible to get the results that you want. Let's go back to Tiger for a second.
In Tiger, we made some assumptions about how the clients were using our framework, or going to be using them. And one of the assumptions that we made was that if you were interested in any of the data that was in the Address Book, you were going to be interested in all the data that was in the Address Book. And so as soon as your application watched, we made sure that all of the information that the Address Book was loaded into memory, it was ready, it was waiting. As soon as you wanted it, it was there.
But no. There are a lot of really great applications out there for OS X. They're all using Address Book to store the contact information centrally and get these great benefits that Brendan talked about. And each one of these applications is interested in a different type of information. If you're writing an e-mail client, you're going to be interested in the e-mail addresses that a person has. If you're writing a Web browser, you're going to be interested in the URLs that they have. Maybe one or two addresses to help them fill out forms quickly.
But the rest of the information, your application probably isn't concerned with. So in Leopard we're going to wait to load information until you ask for it. And there is one thing that is going to be critical to making this work to everyone's advantage. And that's searching. Let me show you how.
Say you're writing an app -- say you're writing an e-mail application. And you want to build a quiet list out of all the e-mail addresses that a person has in their Address Book. You might have a loop something like this. We're going to use the new four in syntax as part of Objective-C 2.0, and we're going to ask the Address Book for a list of all the people that it has.
We're going to iterate over the array that comes back. And we're going to ask each person for the e-mails that they have. And we're going to add those e-mails to our writing list. Now let's look at this from a memory access standpoint and see what's going on behind the scenes.
At the beginning of the loop you asked the Address Book framework for a list of all the people. So we'll go to the disc, we'll get you a list of all the people in the Address Book. You go into the loop. You get to the first person, you ask us for the e-mail address for person one. We'll go to the disc. We'll get you the e-mail address for person one.
You get to person two. You ask us for the e-mail address for person two. We'll go back to the disc, we'll get you the e-mail address for person two. We'll go back to the disc and we'll get you the e-mail addresses for person three. We're not going to second-guess your application and try to predict what kind of information you're interested in.
We're going to wait until you ask for information before we go to the disc and get it for you. And as a result this loop is going to end up spending a lot of time waiting on disc access; waiting for us to come back. How does search make this better? Let's go back to the beginning of the loop. If you just ask us for a list of all the people we don't know what you're interested in next.
But if you ask us for the people who have an e-mail address, that gives us a clue. I mean, wow, you're probably interested in the e-mail data. So the same trip that we go to the disc and we get you the list of people who have e-mail addresses, and just people who have e-mail addresses, we can also get that e-mail data at the same time.
And then the loop can go through and it doesn't have to touch the disc again because all that data is already in memory. And only the data is -- that you're interested in, that e-mail information. Only that is in memory. You don't have to worry about the rest of it.
How much faster is this? I mean, you might be thinking, okay, there's a little bit of overhead involved in creating the search and executing the search. Certainly, for small data sets it's faster to just grab the list of everybody and just blindly walk through it. And you're right.
A little proof of concept app, just to play around, take some measurements. And how many of you have at least 10 people in your Address Book? Yeah. That's how slow it is to go back to the disc all the time on every pass through the loop. If you have just ten people in your Address Book, it's faster to search.
Now what if you have more than 10 people. What if you have hundreds of contacts? What if you have thousands of contacts? Well, turns out that, yeah, searching is definitely faster. It's a lot faster. Now how much additional code do you have to write in order to get this performance? Well, not much. Just two lines. Let take a look at them.
The search element is a description of what we're interested in. Here we're interested in all the people who have an e-mail address. We're not worried about the label. We don't care if it's a home address or if it's a work address. We're not worried about that. We want them all. We don't need to use the key. The key is used if you're searching street addresses. Let's us know if you're searching the street value or the city, or the zip.
Don't need to use that here. Just want all the people who have an e-mail address. And then instead of asking the Address Book, you know, for everybody, we ask the Address Book for the people who have an e-mail address. Again, we get back an array. And so our original loop doesn't have to change at all.
But because you searched, the Address Book framework has been able to preload the data that you're interested in into memory and so you get faster performance using less memory. Searching is something that works in Leopard, also works in Tiger. So if your application targets both versions of OS, don't worry about special-casing anything. You can -- the same code will run on both. Let's talk about something that is new in Leopard.
Brendan mentioned that new in Leopard we're now using CoreData on the back end. Simple database engine. One of the fun things about sequel database engines is we've made these little sand boxes to play in. And you can get the data, and you can play around with it and make all the changes that you want to it. And when you're ready, you have control over when that information is saved and made available to anybody else that's using the databases.
So new in Leopard, and in addition to the shared Address Book object, we're also introducing local Address Book objects. They have the same data available to them. But whereas the shared Address Book is available to the entire operating system, any application that's running, a local Address Book object is only available to your process within whatever method you're using it in.
When you make changes to a record that's in the shared Address Book, those changes are immediately visible and available to other applications. With a local Address Book object, you have control over when those changes are made available. This additional control does come at a little bit of a price.
Because there is just one shared Address Book object, once it's initialized, it's initialized. Anybody can get it, anybody can get it for free. Any time you want to create a local Address Book object, it does take a little bit -- it does take a little bit of time for us to set it up; get ready for you. Not much, but it can ad up. So there's one place that I want you to be aware that we're doing this behind the scenes. And that's when you create a record.
In order to get future pairing between Leopard and Tiger when you create an -- when you create a record using the emit method we will create a local Address Book object to create the record in; set it up. So new in Leopard we're also going to introduce an emit with Address Book method. And this will let you specify which Address Book object you want us to use. Let me show you how this can work -- how this can help you fine tune the performance of your application. Let's say you want to write an H card parser.
You've got code that loads the X M data into memory and parses it on to some sort of a temporary data structure, maybe an array of dictionaries. If you do the Cocoa development, a dictionary is just a hash table, a map associated with an array. And once you're satisfied that you got good information out of it, you want to take any temporary data structure and store it into the Address Book. Let's start with a loop something like this.
Nothing fancy. We're just going to go through our temporary data structure. We're going to create a local person -- we're going to create a person. We're going to go through and we're going to populate the person with values that we've got on temporary data structure. And we're going to add that person to our Address Book.
Now let's go back to the emit method where you created this. Like I said behind the scenes, we're going to do this. This is the equivalent code. Does the same thing. Create a local Address Book object and we use that local Address Book object while you're initializing the record. This let's you make all the changes that you want.
And then you control when the Address Book -- when the record is added to the shared Address Book. Now each time through of the loop here we're going to set up and create a local Address Book object for you just to throw it away and create a new one at the beginning of the next loop.
Well, one optimization you can make to this loop is to just manually create a local Address Book object before you go into the loop. And then we can reuse that same local Address Book each time we go through the loop to set the records up and initialize them. There's another optimization you can make in this.
When you add a person to the Address Book, there's an implicit save that goes on behind the scenes. Well, because we have a local Address Book that we're working with, let's just -- instead of saving, saving a change to the shared object every time we go through this loop, let's just save that local Address Book, once we're done going through the loop.
When you save, the changes that you've made are going to be made available to other applications of that shared Address Book. When you save changes there are notifications that are posted to other applications to let them know that there are changes available. By just saving it once at the end you save your application work, you save other applications on the system work. Everybody wins. Everybody's code runs faster, your code uses less memory.
Let's go beyond the framework for a second. When we created the Address Book framework we didn't think of everything. We didn't try to think of everything. What we provided is a quick and easy way to store and access the types of information that -- that applications are most interested in when they're dealing with people.
But -- let's say your application needs to start with more information. You want to do something that sets your app apart from the competition. Well, how do you store more information? There are a couple different options available to you, and which option you use is going to be depend on the specify needs of your application. One thing that you can do -- let's say you want to store information about a person's favorite food or what kind of music they like; what their favorite color is.
The quickest thing to do is use custom properties. You can create a custom description of what type of -- a new type of information that's going to be associated with -- with a person in the Address Book. It works for groups as well. This does have its limitations. For example, because the sync schema doesn't know about these custom properties, you know, custom properties wouldn't be able to sync around.
But for just, you know, access on the one computer, this is going to be fastest and easiest way to do it. But let's say that you do want to have data propagate around, you do want to get it in sync. You do want to get it out on other computers; other devices.
Or let's say you want to store more complex information. You want to store more than just information about a person. You want to store, you know, an order history with a complete call log of interactions you have had with customers. Well, your application may need to use a generic staple database. CoreData is a great framework to use. It's pretty easy to get up and running with it. And a custom database solution can coexist side by side with the Address Book framework just wonderfully.
Every person and every value, like Joe mentioned, had a unique I.D. on it. And so as your database needs to store references back to particular people and items of data in the Address Book database, you can use those as a reference. They persist. They stay around. Or you want to go really complex. Or maybe you've already got an existing database solution that you use with your application.
You've had it for years, you've invested a lot of engineering time to fine tuning, you've got the performance you want. It's tried, it's trusted. You're a little bit hesitant about, you know, getting in and tearing things apart. Well, going in with sync services is another option. There's a public sync schema for contacts that will let you get the information from your database into the Apple Address Book ecosystem so that users can pick up on these events, OS X technologies that Brendan was talking about.
Also let's your application pick up information that users have already entered in another application. That's another option that's available to you. But for most of you, the fastest, easiest way to get your application up and running is sharing address information with other applications on the system is going to be through using the Address Book framework.
You get advantage to these new OS X technologies as they become variable. When Tiger came along, anybody who was already using the Address Book framework they got Spotlight for free. Anybody who is using the Address Book framework now is going to get Time Machine for free. Syncing to other devices. As other devices come along, syncing dot Mac services. Syncing to dot Mac. All for free.
People Picker -- gives you familiar user interface so that your customers can get up to speed faster with your application. They already know it. They can get going with it. And searching. Searching the Address Book whenever possible gives us clues to the kinds of data that you're interested in, so that we can have the data ready for you when you need it, still using as little memory as possible.
So where do we go from here? Well, 5 o'clock any afternoon we're going to be down in Mac OS X Lab A. And we would love for you to come by and spend some one on one time with us. You know, talk with us, any questions, concerns that you have, stop on by. There's also our developer Web site.
Developer dot Apple dot com. It's got some great code examples and mailing list archives for people who have already gone through and solved maybe the same problems that you're facing now. It's always available, 24-7. There's also Matt Drance, our sharing technologies evangelist here at Apple. He doesn't keep quite the same hours that the Web site does, but he is available now.