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-123
$eventId
ID of event: wwdc2005
$eventContentId
ID of session without event part: 123
$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 123

Introduction to Core Data

Application Technologies • 59:23

Core Data dramatically simplifies development by handling the management of your application's data objects, both in memory and on disk, allowing you to focus on your application's logic. Learn about Core Data's architecture as we walk though code examples and use Xcode's design and modeling tools to build Core Data-based applications.

Speaker: Matt Firlik

Unlisted on Apple Developer site

Transcript

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

Good evening, and welcome to session 123, Introduction to Core Data. My name is Matthew Firlik, and I am the manager of the Core Data engineering team. Show of hands to start with. How many people know nothing about Core Data? Zip, zilch, nada, zero. Wow, you are in the right place. How many people of you have used Core Data a little bit and want to know more information about it? Decent.

Now, be honest, how many of you people know a lot about Core Data and are here to ask the really difficult questions in the Q&A? Thank you for being honest. You can leave. All right, so introduction to Core Data. First question, what is Core Data? You may have actually looked online, seen websites, seen lots of descriptions of Core Data, and they're a mouthful.

Lots of words like model view control, object graph management, persistency. These are very, very, very sophisticated terms, and we certainly do all of these things. But let's actually just take it down to basics. What does Core Data do? So it's a framework that allows you to interact with your data. And we're going to break that up into three different parts.

First is the visualization and the display of your data. Obviously, you have something interesting and you want to display it through your application. That could be physically putting strings on the screen in text fields and table views, or that could be using lots of numerical information to represent some kind of graphic.

But you want to visualize your data. Second thing is you want to create, modify, and delete your data. Data is more interesting when we do things with it. And then the last thing is you want to save and retrieve your data. Take all this stuff that you've put in your application and bring it back.

So these are the fundamental tenets of Core Data. And as you start to look at some of the descriptions, we'll actually go through and we talk about modifying objects and creating and deleting. That's really the object graph management part. So when you see that term, that's really what that refers to. And when we talk about persistency, it's the saving and the retrieving part. It's figuring out what to do with your data and how to get it back to you when you want it.

It's important, though, to remember that Core Data is all three of these things. And you don't necessarily have to use all three of these things. You can use any mix of these to provide benefits to your application. So don't think just because, "Oh, I already have my data in a file, and I don't really need any of this.

This isn't useful to me." You're going to be very surprised. So... Down to the basics. So we're talking about taking a piece of data and putting it in an application. In this example here, we're going to talk about a little bit of XML and we want to put it into an interface, maybe something looking like iTunes.

The framework provides you the benefit of doing this through something which we call managed objects. And you'll start to hear this word "managed" going through the entire presentation. Managed objects give you the power of taking data from somewhere and getting into your application and using it very, very quickly.

So to describe this, we're going to take a look at the Core Data architecture. We're going to call this the persistence stack. And we're going to burn this into your memory by the time you're done. And if you can remember this, you've got Core Data pretty much down.

So we're going to call this the persistence stack and we're going to walk through this for pretty much the rest of the presentation. So let's start at the top and we're talking about managed objects. These are objects that encapsulate your data, encapsulate behavior, encapsulate logic, that give your application power, power to do something interesting, power to do something compelling.

The framework also provides you things called fetch requests, which pretty much, as the name implies, allows you to ask the framework, how do I get something? Go find something for me and bring it back so I can work with it. So you don't have to keep track of things.

You can let the framework do that for you. There's a managed object context, as the graphic implies. It's kind of a drafting table. It's a scratch pad for you to work with your objects, create them, modify them, delete them, throw them away, do whatever you want with them. But that's kind of your playground.

Another important element is the managed object model. This is a blueprint. It's kind of your contract between your application data and the framework that-- along with the persistent store coordinator figures out how to take your data from your application and put it somewhere interesting and then get it back to you. And obviously, on the very, very bottom, we're talking about the persistent store. This is where your data is physically stored.

So that's the Core Data stack in a nutshell. And we're going to go through this for the rest of the presentation. In the upper right-hand corner, you're going to see a small graphic of this as we go through with little sections highlighted. So in case you get lost or in case you want to see exactly where this lays within the architecture, you can follow along there.

Now we're also going to be talking about a lot of things that Core Data does. So from the undo management to working with Cocoa bindings, grouping and filtering, validation, integrity management, persistence, putting stuff into SQL, putting stuff into XML, it does a lot of things. And it does them all very well. But I want to reiterate the point of use as much as you need from this framework. This framework provides a lot of functionality, but it's not totally inclusive. You don't have to use all of it. So please remember that as we go through.

You're going to start to see a theme though as we go through. If you look in the WWDC sample code, there's a section called Core Recipes. That is the Core Data section for the conference and includes a number of really, really handy things. One of them is all the hands-on samples that you're going to use for the 9:00 AM session tomorrow that you're all going to be at to look at Core Data.

Includes command line and GUI applications that use Core Data. There's also something called Core Recipes, which is our iTunes-like application to allow you to manage recipe information. And in addition to using Core Data and bindings, it's got some spotlight integration and it's got an automator action. And then there's also a migration example to talk about how to take stuff from one schema and move it to another for those people that have already reached that pinnacle of Core Data.

Let's get started and talk about the persistent store. So the persistent store is obviously where your stuff is saved. And logically, it's a file or a collection of files where all of your information is stored. Now for the most part, the persistent store is transparent to both the developer and to the application.

So there is some information about the persistent store. Core Data remembers a unique ID about the store and also knows about a type. We'll get to that in a little bit. But there's no API on the persistent store. Please don't go look for NS persistent store in the class hierarchy. It's not there. What you want to do is use the store coordinator. That's where all the power is.

Now, you have a number of options when we talk about stores. There's different types, and there's different characteristics of those stores. We'll talk about the first one, which is XML. How many of you have actually used XML before? All right, so XML is good. It's very human readable.

You can actually go ahead and look at it. And it provides actually decent speed for Core Data. We also have a store that's a binary store, which uses an NSKeyed archiver format to go ahead and store your data. Little bit better performance than the XML. Now, both the XML and binary stores use what we call atomic access. Obviously because these stores represent an encapsulation of data is that we need to read the entire file in when we load the store.

It also means that when we save data, we need to write the entire store out. So you can imagine if you have a big graph of data and you want to save one thing, change one thing, and it's in XML, we need to write the entire XML file out or the entire binary store out. So obviously this has performance implications and it has speed implications.

So we offer another store type, which is a SQLite store. The SQLite store does not have these limitations. We can read it in just the small bits. It offers extremely good performance because we can actually use some of the benefit of SQLite to perform some operations. So for extreme scalability, you want to go to the SQLite side, but you may want to start with the XML store when you start working so you can actually look at the data that Core Data is creating for you.

It's important to note that just because you start with one store doesn't mean you can't move to another. So there is API to migrate data from one store version to another, so you could start with XML and end up in SQLite without having to do that much heavy lifting.

One of the unsung heroes, though, of Core Data is the in-memory store. So as the name implies, this is a store with no physical backing on disk. So when you put stuff into the store and you save, it's just staying in memory where you put it. But when you think about this for a second, this is an extremely powerful feature, because that means all of you out there right now that have existing file formats, existing pieces of data, can actually go ahead and create managed objects out of those and put them into the in-memory store.

So you can take your persistent file, put it in an in-memory store, and take all the benefits of Core Data-- undo management, integration with Cocoa bindings, everything you need. And then when you use the framework to get the notifications when your information is saved, you can go ahead and write that stuff back out. So this is one way you can leverage Core Data, even if you have an existing file format today.

So there's the question of, well, how many stores do I want to use? So there are applications like iTunes and Address Book, where it's a collection of data. All the data is stored in one place, and in some cases, it's related to one another. Core Data allows you to do that very, very easily.

But when you think about it, these applications also use many stores collaboratively. You share your Address Books. You share your iTunes music. So it's using the same blueprint of data, the same kind of data, and putting multiple things together so to the developer or to the user, it looks like one thing.

Core Data makes this very, very easy to do. Additionally, we also provide you the ability to use separate stores, for example, in a document-based application, where your information isn't related to anything else. It's all just one piece of data. Core Data provides you that as well. And if you're interested in document-based applications or you have one now, there's a class called NS Persistent Document that you're going to want to take a look at, because we've implemented a lot of the heavy lifting for you, and you can just go ahead and leverage that with Core Data.

So then there's question of, how many stores should I use in my application? And the answer is, it really depends on what you're designing. So if you have an application that's just using a small collection of data that's all interrelated, you're going to want to use one store. But then you might want to consider, is it necessary or is it possible to share this information? Can I have people keeping copies of their own libraries or groups of information and having the application pull it together? You want to consider that.

When you do so, remember about dependencies, is that when you start creating stores that depend on other stores being there, that's where your application gets a little more complex. So be aware about that. But then document-based stores are really good for applications where I just want to create a document, I want to allow my users to create things over and over and over again, and they really don't interrelate.

Let me give you an example. When we were creating our Core Recipes application, this is an application to manage recipes. We're putting information into the application and allow people to look at it. So the question is, how do we design this? So we first thought about, what about separate documents? Kind of makes sense. You're working with something like Word. You want to just create a document, type in the recipe. All makes sense.

But then we came upon the problem of, well, what about chefs? What about the people that create the recipes? If I have four or five recipes from the same chef, I don't really want to have to type in the chef name over and over and over again. Makes more sense to just type that in once and be able to use that information over and over. So we decided to put stuff into one store.

But then we realized that even better was a lot of people want to share recipes. So we want to be able to have separate applications, instances, one for you, one for me, one for somebody else. Or I could take your recipe file and just bring it in my application and it loads it automatically. So the example that you'll find on your CD actually is an implementation using multiple stores with one model.

So I just mentioned Managed Object Model. Let's talk about that. So your Managed Object Model is the blueprint. It's the blueprint for your data. So it helps Core Data understand what the high-level schema is, or high-level view of your data is. And if we look at the two top-level elements within a model, they are entities and they are properties. Entities represent a classification of object, if you want to think of it as a runtime representation.

And entities also have properties, which are characteristics of entities. And a property can be one of two kinds. It can be an attribute, which you can think of as just an instance variable. And it also has relationships. And relationships are managed references to other entities. And those can be in the single form. So one object is related to a single other object. Or they can be in the too-many form, where one object is related to many other objects.

Let's take a concrete example from this, and we're going to use the idea of our recipes. So you're looking at a book of recipes, and you've got a recipe here. It's got a name, it's got a chef, it's got ingredients, and it's got a description. So how would we model this? How would we go ahead and create a blueprint for our application to use? So the first thing we might do is say, well, let's just create a recipe entity, and let's just put a bunch of attributes on it. It's going to put the name, we'll put the chef name, some directions, maybe a cooking time, and go ahead and represent our data this way.

But as we start to look at this, we notice a couple things. First is the chef name. I just got done mentioning that if I have a number of recipes from the same chef, I don't want to type this information in over and over and over again. Doesn't make sense.

It's very difficult if, for example, the chef gets married and changes her last name, I have to go and change it in every single place that that chef is placed. What we really should do is instead So, in this case, the white line indicates that's a relationship from the recipe to the chef.

And it looks to the developer like it's another property. So, if you ask for the recipe and you ask for its name, it will probably return you a string. But if you ask the recipe for its chef, it's going to return you a chef entity. So, continuing to look at our recipe, we also decided to put ingredient list on our recipe, which doesn't make any sense at all, because it's a collection of things. It's a big grouping of things, and we should probably separate these out.

So, in this case, we're going to create a relationship called ingredients, and ingredients is going to go to a relationship to an ingredient entity, and the ingredient is going to have the name, the amount, and the measure, like teaspoons or cups. But in this case, you see the double arrow that indicates it's a too-many relationship. So, a recipe in this case will have many ingredients, but one chef.

So the managed object model gives us the ability to provide this kind of blueprint to our application to say, this is what I want my data to look like. This is how I want my data to be used in my application. Now, it's important to remember, I just talked about too many relationships. Too many relationships are returned to you as sets.

They are not returned to you as arrays. Think about that. They're sets. They're completely unordered. So if order is important to you, you need to consider that when you create relationships and when you create your entities. And you'll hear more on that in some of the later sessions.

So what happens at runtime? We take this blueprint, we grab some of the data from the store, and we actually go ahead and create something that if you printed the description out, it would look like this. So this may look like a little bit of a gnarly information, but it's basically saying, this is a recipe.

It's an entity for Core Data. And you can see it has some attributes. It has a name, and it has some cooking time. And you'll see that in certain places, like the ingredients and the chef, it looks like it's referencing another entity. So this is how your information will look when you work with it.

If you spent more time on this model, you might get something that looks like this, which is the representation as you'll see it within Xcode when you design a Core Data model. So you can see here, you can create a relatively sophisticated view of recipes and cuisines, ingredients and measures, all sorts of things. If you want to take a look at this in the Core Recipes application, there's a Core Recipes model that'll give you a complete view of what we created for our application.

And it's important to note that a model actually does more than just define entities and attributes. It actually defines quite a bit more. You can define default attribute values. For example, every time I create a recipe, I want the name to automatically start out as new recipe. This is great for giving users hints on things they need to change. It's also great for filling out attributes that they may want to change, but in most cases, they don't need to. So you can provide them the benefit of not having to change those values.

The model also provides you with the ability to set up rules, things like validation rules, what things have to be there, has to be between a certain value range to be able to be saved. Things like deletion rules. If I delete a recipe, should I delete the chef too? Answering some of those questions and even customizing the model to store custom information that you want to use in your application based on the entity.

All models are represented by a class called the NSManagedObjectModel. You can create these in Xcode, but you can also create them programmatically. And there are some number of examples where we do create models programmatically and the number of benefits to doing that. I can't stress this enough though, is that your model is absolutely critical to the success of your application.

When you think about it, it's the contract between you and Core Data that sets up guidelines and policies for how things work. It sets up how your data is related and how data interacts. It also helps the framework maintain integrity on what things are supposed to be in what ways. So your model is really, really important.

Your model needs to be designed with both function and performance in mind. So when you think about designing a model, think about what does my information look like and how do I want to use it? You can imagine if you put all of your attributes in a single entity, it makes it very easy to get at, because you can just fetch one thing and it's all right there. But from a performance perspective, that's not really good for searching.

Because if I want to search on just one thing and see some quick references in a table view, I've got to fetch the entire entity back. So you want to think about both performance and function for your model when you're creating them. And there'll be more on this in some of the later sessions.

But never fear. The more complicated your model, the better Core Data does. Trust me, the framework is really good at dealing with models. And the more complex things you can throw at us, the more power you're going to see out of the framework. So don't be afraid to create something that looks a little scary if it's really what your application needs.

So I'm going to get this out of the way. What about making changes to my model? So when you create a model, as I said before, it's a blueprint. And we use that to go ahead and create the underlying store. If you go ahead and you create a blueprint and you use that blueprint to put data into a store, application works just fine. Now you go ahead and you make changes to the model. And then you start your application back up.

Core Data now says, huh? Because the Blueprint is now different. It now expects something completely different based on the Datastore does not match the Blueprint, and we get a little confused. So consider that. It's actually something good to consider when you actually just create your own application, about versioning. I create version 1 today.

I'm going to create version 2.0 maybe six months from now, and my data may look very different. How do I deal with that? How do I deal with the fact that my model may need to change, and my application may need to be smart enough to say, this is what my data was before. This is what my data looks like now.

You're just in luck. We actually happen to have sample code that actually deals with some of this. There's an example called the migration. It has a generator and a migrator, which actually will generate some data in one model, create a new model, and show you how to migrate the data from one to the next. So please feel free to take a look at that.

But enough of my talking. Let's actually look at a real demonstration of building a model. And so for that, I'm going to invite Adam Swift, a Core Data engineer, to show you creating a model within Xcode. Adam? Okay, so we've got recipes and we want to build an application to manage them. So I'm going to open up Xcode 2.1, which provides some tools to do that. There are a variety of templates for projects. I'm going to choose the Core Data Application project because this isn't a document-based project.

The first thing we see when we open up the project is it's created some code in the classes, some models, and some other resources that I'll use later. For now, I want to create the model. So the first step is to open up the Model Design Tool. And you can see this window is divided into two major parts. At the bottom, we've got a graphical view, which shows a sort of bird's eye view of our data model.

I'll bring that up a little closer. And then in the top half, we've got some detailed lists and tables, which allow us to edit the data model. A lot of these controls, and you can see there are a lot on screen, are available through the menu using the design data model menus.

To make it a little easier to follow what I'm doing, I've customized the toolbar on this window to add the entity, add attribute, and add relationship buttons. So the first thing we want to model with our recipes is the recipe itself. And as Matt described, that's an entity. So I'm going to create an entity here. I'll go ahead and rename that.

And you can see in the entity list that name change is reflected. And the first thing I want to do with this is add the attributes that define my recipe. The most obvious would be the recipe name. Now, when I select the recipe entity here, you can see in the property list it has the name listed as an attribute, but the type is not defined. The name should be a string, so I'm going to go ahead and set that. Some other attributes of a recipe are the directions and the last time I prepared it. I'll go ahead and set those.

Directions is another string. And the last prepared date I'll configure as a date. So that's a start. Now another part of my model, the data of my recipes, is the chefs. And we decided that a chef is a complicated enough piece of the model that I wanted to make it an entity all its own. And also, I want to add the ingredients. I'll go ahead and rename these.

And I'll set up the chef with a first and last name. And one of the nice features of the tool here is if I select both of these attributes, I can modify their type together to set them to string. For the ingredient, something like one cup of sugar, I need to add the amount, the name, and the measure.

The amount is a number, so I'll select decimal. Name is a string. And again, measure something like a cup or a tablespoon is a string. So now I've got my major entities here. I'm using a simpler model than Matt suggested for the purpose of the demo. But the recipe doesn't know its chef, and the recipe doesn't know its ingredients. So I'm going to use a-- The button here on top to add a relationship to Chef from recipe.

And you can see in the property list, it's created a new entry here called New Relationship. I'm going to rename that Chef, and I want my Chef relationship to be to the Chef entity. And you can see when I select the entity, updated the graphical view below with an arrow connecting recipe to chef.

To connect the ingredients, I'm going to use another feature of the graphical tool, which allows me to draw the connection from recipe to ingredient, where it automatically fills in the destination entity based on the connection I drew. I'll name that ingredients. And because, except for boiled water, I always have more than one ingredient, I'm going to set that to be a too many relationship. This means that a single recipe will have multiple ingredients, will be able to know about multiple ingredients.

So right now I have the basic information for my recipe. I have a chef, I have a list of ingredients, I've got a name and some directions, but I want to be able to do some other things with the relationship between the chef and the recipe. For example, if I have a chef, I'd like to know all the recipes that the chef is responsible for. So I'm going to create a relationship from chef to recipe called recipes.

I set the destination to be recipe. And now you can see in the window below, it's created that connection. I'm going to set that to be a multiple-- a too many relationship. And now you can see that my chef knows about multiple recipes. When I think about it, though, the recipes I've got The chef-to-recipe relationship is really two sides of the same connection.

Now, one of the things I can do in the modeling tool is to inform my model that these relationships are really representing two sides of the same connection. And I can do that using the inverse relationship here. When I make that change, you can see in the graphical view that the two connections have become one with two endpoints. It's still two relationships, one from chef to recipe and one from recipe to chef, but it's represented as one thing because they're connected.

So I've got a basic working model right now, and I could leave it as it is. But there's some other nice things I can do with the modeling tool that will help me build a better interface and help my users understand the data that they're working with. So if I select the recipe and select the name attribute, I might want to put in a default value for the name, such as recipe name. And I might want to enforce a rule that the recipe has to have a name, so I can check off optional to ensure that a recipe can't be saved without a valid name.

Another thing I can do is make my directions non-optional and also set a minimum length for the directions to be five characters and a maximum length to be 5,000. This will assure that the directions are always a reasonable size. I'll set a default value to say, please fill in the directions here. And now I've got a pretty reasonable basic model that I can work with, and I'm ready to get started on the next step of building my application. Thanks, Matt.

Thanks, Adam. So we've just seen creating a simple model. Now the question is, what do we do with this model? Well, the model is one of the crucial pieces for the persistent store coordinator. The Persistent Store Coordinator is essentially the framework's middleman. This is, as the object is named appropriately, it coordinates moving objects between the stores that we just saw before and the developer, so the managed object context that we'll hear about in a little bit.

We were commonly referred to this as the PSC, so if you hear that phrase, that's what we mean. The Persistent Store Coordinator synchronizes access to all of the persistent stores. So this means if your application has more than one store and you're using one persistent coordinator, it's the one that synchronizes all the information back and forth between those stores.

When you're using a managed object model and you're using multiple stores, you can actually specify which stores contain which pieces of data. Now, you could actually save the same pieces, same kinds of data across all the stores, so you could basically create a striping design where lots of pieces of information that all look the same are stored in different places, but there is no support for mirroring right now. So you can't create a copy of one store in another.

So the persistent store coordinator basically is the facade in front of the stores. So it basically works by taking the managed object model and we plug it into the coordinator. And at this point, the coordinator allows us to go ahead and load stores. Now, as I just said, the managed object model represents the kind of data that we're working with. And so you can use the same model and the same coordinator to load more than one store.

So I'm going to reiterate that again. You could actually keep the same kinds of data in multiple stores

[Transcript missing]

So we load one by default. But you'll note in the left-hand view, there's this little section called imported. What we do is we've actually defined a UTI type for our stores. And using the wonders and powers of Spotlight, we actually create a Spotlight query that knows how to go and find all of those stores based on the UTIs. And we automatically load them.

So in essence, what this allows you to do is take your Core Recipes application, go ahead and put some recipes in it. Now copy your recipe store onto a shuffle, walk over to somebody else's computer who's using Core Recipes app, and just plug your shuffle right in. Spotlight is going to tell the application when that store comes up, when the store is found, and our application is automatically going to load it and bring it in. So it's a really, really neat integration of both Spotlight and the ability to load stores within Core Data to show you how to interact with application data.

While we're talking about Spotlight, what is this metadata thing? How many of you guys have written Spotlight importers yet? How many of you want to? Come on, there's got to be more than that. It's a cool thing. So Spotlight and Core Data are complementary. They're both dealing with data, but in very different ways. Core Data is about the data inside of your application, all the nuts and bolts. Where Spotlight is more about the metadata. It's these small, interesting tidbits about your application that you want other people to be able to search on.

The Persistent Store Coordinator provides very, very easy API to read and write metadata that you can then use with an importer. So you can actually go ahead and look at the NS Persistent Store Coordinator API for that. It's very, very simple. It's metadata for Persistent Store. And you can actually look in, again, the Core Recipes application. We have a Spotlight importer target that creates an importer for our application.

Now, at this point, I need to add a standard caveat, which is there's always a question of how much metadata do I store? When you think about it, if your application has a lot of data and you want to create a lot of metadata, you now have two copies of your data. Your store may actually be very, very big if you store a lot of metadata alongside of your regular data. data.

You may be tempted to say, you know what? Maybe I don't actually store my metadata ahead of time. Maybe I just go ahead and create a Core Data persistence stack inside my importer, go ahead and figure out all the data, and go and shove that off to Spotlight.

You may be thinking that, but I would encourage you not to, in that creating a persistent stack is not necessarily an inexpensive operation, and your importers need to be very, very thin and very, very fast. So consider very, very carefully when you're creating your spotlight importers about how much data you're saving and how you're doing it.

So once we've got our data from our store, and we've got it through the persistent store query, now we want to do something with it. So how do we do that? We do that through the managed object context. And the managed object context is, as it says, it's a drafting table for your data. This is the workspace of the framework.

When you ask for objects from the framework, it's going to give them to you in a managed object context. When you want to save them or you want to revert them or undo them, you do so in a managed object context. And the context is kind of the gatekeeper of all the notifications that happen when things get saved or things get deleted. That's where you're going to get them. You should consider it a scratch pad for working with your data, because you can undo and revert changes at any time you want.

So you can go ahead and make five, six, or seven changes, back out three of them, make a couple more, and then throw them all away. So it really is the place where you do a lot of your manipulation of your data. We commonly refer to this as the Mach. So you have two terms, Mach and PSC.

So when we think about it, we're going to talk about going ahead and grabbing data from our object store. The persistent store coordinator is going to go ahead and take those objects, hand them over, and put them into the Manage Object Context for us to use. Now we can go ahead and we can create changes with these, make changes, add new ones, delete them, and at any point in time, to reiterate, we can go ahead and just throw those away.

Don't want those, just throw them away. However, we can also keep those changes, tell the context to save, which in turn is going to hand them back to the persistent store coordinator, and it's going to go ahead and just put those right back into our store. It really is that simple. And it's all just telling the Manage Object Context what you want to save and when you want to save it.

We've talked about multiple stores. Let's talk about multiple Managed Object Contexts. So in this case, you'll see we have lots of stores here. But you can go ahead and use multiple mocks when you create your application. Now you may have a question of why would I want to do that? Well, let's take another example of our Recipes application. We have an interface that lists all of our recipes.

But I want to go ahead and double-click on a recipe, and I can look at it, and I can make modifications. We use one Managed Object Context per Editor window for a recipe. Now the benefit to this is that we can edit any recipe we want and save it and know that we're just saving that piece of data.

You can imagine that if we started out, we had one Managed Object Context, and I say I want to work with three recipes. I open up each one. I make changes to two of them that I'm not quite done with. I open up a third. I make the changes I want, and I save.

You're saving the third one because you're done with that, but you're also saving the other two because they're in your Managed Object Context. So you want to use multiple Managed Object Contexts when you want to segregate your work so that you can work on separate things in separate places, and then you can commit your data at whenever point in time you want. Now there's some heady things that go along with this about what happens if I'm working with the same object in multiple contexts at once. Framework really knows what to do, so don't be worried about that.

So we've talked about the persistent-stork-reward-enter. We've talked about the manage-object-context. Let's talk about fetch requests. And fetch requests are how you get objects, how you find them. So the fetch request is, as it states, it's kind of the bloodhound for your objects. It's your ability to specify a query for the framework to go ahead and find things for you. Now, fetch request has three pieces of important information. The first is the entity. So it's the piece from your model that you're looking for.

It has a set of search criteria, the ability to specify exactly what you want to the framework so you don't have to sort through a bunch of things. And it also has things called sort descriptors, which allow you to sort the results when they come back in a particular order, if you're interested.

You can actually go ahead and create fetch requests inside of the model. We didn't show you that today, but you will see that in later sessions. So you can go ahead and templatize, if you will, your fetch requests. And you can include variable substitution in those. So you can make really, really complex fetch requests, storm in your model, and then at runtime just pull them back, substitute in your variables, and go. Now fetch requests are evaluated in the store wherever possible. So we want to go ahead and make sure that we're evaluating things in the place where there's the most performance.

Now, one of those things that I talked about was specifying search criteria. And we do those through the use of predicates. How many people in the room know about NSPredicate? How many have used them before? You guys have a bunch of reading to do. Predicates are really, really handy things to do. And they're not useful in just Core Data. They're useful in a lot of other places. So you can create a predicate programmatically. We talked about defining them in your model as part of a fetch request. They're often based on user input.

So you take things that the user type in, create a predicate out of it, and go ahead and specify it to you in your fetch request to go ahead and search on. They're used outside of Core Data, as I just mentioned. There's API on the NSArray to go ahead and use predicates to filter them.

The metadata API, the spotlight API, uses them heavily. So when I talked about our application being able to go and find stores of our particular type, we created a predicate that matches our UTI type. They're also used in the array controllers very heavily. So if you use bindings, go take a look at predicates. And predicates come in three kinds of flavors. There's the abstract class NS predicate.

There's the comparison predicate, which is just doing a simple comparison. And there's also the compound predicate, which takes multiple predicates together. So you don't necessarily have to create this one big, long predicate that has a bunch of information in it. You can create multiple predicates and put them all together.

So what can you do with predicates? Well, you can do simple comparisons, like name equals soup. You can do things like case insensitive or diacritic insensitive. You can do logical operations. So I can start looking at attributes, first name like something or last name like something. You can use predicates for relationships. So it's not just about objects, but you can walk across a relationship to figure out from a recipe, I'm looking for ingredients with a certain name.

Or I'm looking for ingredients that have a certain amount. You can also do operations on them. So if our ingredients had, for example, a price, we could go ahead and, if you look at the key path here, sum the array of all the ingredients with their price attribute. So if we put an attribute on the ingredients called price and filled it all out, that operation would tell us how much all of the ingredients cost. Or actually, not how much they cost, much they cost, but find them all the ones that cost less than $50.

If you want to look at the application we provide you, we actually use predicates quite extensively. The filter field at the top uses a predicate, so we can go ahead and filter the table view of recipes. We also include something called a Smart Group, which shows you a group of recipes.

And we've included a nice little API to go ahead and create predicates on the fly, so a nice little graphical interface. We use a predicate, as I said, for using Spotlight to find our stores. And there's also something called an inference core, which is kind of a rules system that we've put in that uses predicates very heavily. So if you want to take a look at those, take a look in the App Delegate or take a look in the Inference Core to find more information about those.

So enough about predicates. Let's get back to the fetch request. How does a fetch request work? So again, as I said, the fetch request comes out, and it's going to specify an entity, potentially a predicate, and potentially sort descriptors. So you create one of these, and you create them in your managed object context, and you say fetch.

So what happens? Managed object context takes that, hands it off to its persistent store coordinator, who then goes and figures out, based on the blueprint, which are the stores that has the kind of data you're interested in, which stores have the entity you're interested in, and passes the request off to those. Each one of those will actually go ahead and perform the fetch request and get the objects that match.

In return, the stores will hand it back to the persistent store coordinator, which coalesces all those objects together, takes them from their persisted form into their managed object form, and hands them back to you for you to use. So again, the power of using multiple stores. But a fetch request is just very simply taking a request that you had and pulling information from out of a store.

So let's talk about the Managed Object. The Managed Object is your data workhorse. It's the unit of data that you use to work in Core Data. It's the thing that you're going to fetch. It's the thing that you're going to insert. It's the thing you're going to save and the thing you're going to delete. These are the things that are created as a result of you defining your model. So you actually create Managed Objects yourself when you want to go ahead and insert them. The framework returns Managed Objects to you when you fetch things. important thing to remember.

Each managed object is described by a single entity. So when you fetch something out of the database, when you fetch something out of your store, to be clear, it's defined as by a single entity. It's associated with a single context. It's very important when you think about it.

When you pull a piece of information out, your managed object, it is in one context. That's not to say you can't work with the same piece of data in more than one context. But at that point, you'll have two separate managed objects. So an object only is in one context at a time.

And it has a unique identifier, unique ID. Core Data provides a basic class. It's called the NSManagedObject. And that implements both key value coding and key value observing. How many people are familiar with key value coding and key value observing? OK, good. We provide a base class, NSManagedObject, that provides you a lot of facility with those. Even so far as you define attributes and relationships, and you don't have to write any code at all if you want to use them. We go ahead and use key value coding based on the information in the model to allow you to get that information.

When you create your objects, again, as I said, this is the workhorse. This is where you're going to do most of your work. So it's important to consider options, all of your options, when you're adding smarts to your application. So your managed objects can actually inherit from other managed objects. So you can create a very large inheritance hierarchy in your application.

You can create your own custom base class if you want. You could subclass NSManageObject and implement a lot of functionality there. Or you could actually create custom subclasses for each of your entities. So in our example before, we could have created custom subclasses for recipe that maybe knows how to generate the RTF for the recipe, custom classes for ingredients that know how to do something interesting there, like put themselves in a shopping cart, and a custom class for a chef that knows how to go find a home page or something like that.

So it's important to remember that you have a lot of options when adding smarts to your managed objects. You can use custom managed objects for a lot of things. Validation is a very, very good one if you want to add custom validation rules. Working with derived values, if you want to have a complex attribute of some kind that's generated by another set of values, you can use those. And reacting to state changes. If something changes, especially something that's related, you may want to do something interesting. So you may want to create custom classes for those.

What about referring to managed objects? Each managed object has related to it something called a managed object ID. It's a unique identifier that Core Data uses to, as it pretty much sounds like, identify the object. What about referring to managed objects? Each managed object has related to it something called a managed object ID.

It's a unique identifier that Core Data uses to, as it pretty much sounds like, identify the object. So, I can save data anywhere I want, but I can specify an identifier so my application knows exactly what I'm referring to, when I'm referring to it, and how to get back to it. But it's important to note that URIs are temporary.

I misspoke myself. It's important to note that the URI for a temporary object is temporary. So if you create a new recipe and you try to take the URI for that and hand it to someone, if you've saved that recipe, by the time they click on it, URI is no longer valid. So temporary object, temporary URI, saved object, valid URI. Important thing to remember.

So what I'd like to do is actually bring Adam back up here, and we're going to show you how to put some of these other things together and create a quick application using Core Data. Adam? Okay. So I've done the work to put together a decent model, and now I want to build an interface for it.

I'm going to go back to my project, make sure I save my model. And the project builder template, or Xcode template, for this project created a interface file for me. I'll bring that up. And you can see there's the project window, an empty window it created for me, and a menu. Bring up an inspector.

So what I'd really like to do, I've spent a decent amount of time defining a pretty reasonable model here. I'll close this to focus on the part I want to show. I'd really like to be able to take all the information I put in about my recipe and build a model directly from that. The good news is that's exactly what I can do. I'm going to option drag my recipe entity from the graphical view and drop it right on the interface builder window.

When I do this, it's going to ask me what kind of interface I want to create. I want to create an interface for managing many recipes, so I'll select many objects. And when I do this, it's going to put together a fully working interface for me. It's really powerful. This isn't a canned thing. It's actually doing a lot of work that I could do by hand.

I'd like to explain some of the things that happened right there. So let's look at the left side. There's a recipe array controller, which is going to be used to provide the values from the data store. in the interface. And I defined, if I look at what this really is, it's a basic array controller using bindings configured to use the recipe entity.

And because in my model I defined some values like directions, when it was last prepared, the name and the chef, it's put together a usable interface for me including these items. Now, I can go ahead. This is a standard table view. I can reorder the items. I can resize. I can manipulate them to make my interface look the way I'd like. And everything's going to work just the way it should. For example, I might want to have the name above the directions.

And And there are some other parts in this interface that I had put together for me. For example, this add button. is actually connected to the recipe controller, so it will automatically ask the controller to create a new recipe entity for me. is actually connected to the recipe controller, so it will automatically ask the controller to create a new recipe entity for me.

So I think I'm ready to go ahead and try out my application. Oh, there's one other thing I'd like to do. The application will automatically save when I quit, but I'd like to set up control to save when I want to. So I'm going to connect the Save button to the action on my application delegate. OK, now I'm ready to go. Go back to Project Xcode.

Historical problem. And go ahead and build and run my application. Okay, when I click the build and go, it's going to compile the data model, the class files, and the interface into a real live application, and I can go ahead and start adding recipes. Historical problem. And go ahead and build and run my application.

Okay, when I click the build and go, it's going to compile the data model, the class files, and the interface into a real live application, and I can go ahead and start adding recipes. And set the directions to ask mom nicely to make French toast. And there we go. We've got one recipe. Let's add another one. We'll make that boiled egg.

And the directions are boil and egg. OK. Now I can go ahead and hit the Save. And we'll save my data. I quit. Run my application again, and there you go. Saved my names and recipes. So to prove that this is actually doing something other than faking a demo, I'm going to go and look at the data file that it created.

Which by default is stored in the application support directory under the application name. And I've chosen to use the default data store, which is an XML file. When I bring this up, You can see there's my French toast and there's my boiled egg. I can edit the data in here if I want to, to say French toast. No, I want pancakes.

"I save that data file, and when I rerun my application, you can see I've got pancakes, which I can ask mom for." So if you remember when I set up my data model, I spent some time adding some rules about what were required fields and what limits there were on what data could go into them.

So if I go ahead and just delete the name and I try to save, It's going to tell me that name is a required value. Again, this is with no code. It just followed the rules from my data model, and thanks to bindings, gave me some useful feedback. So I'll put that back to pancakes.

And I'll change the directions to some, I'll delete the directions. Again, if I save, It tells me that directions is a required value. Also, if I tried to set directions to be something short, is going to tell me that directions is too short. That's because I set the rule that directions had to be at least five letters long. Okay. So now I can save. And there we go. We've got a working application. Thank you, Matt.

Thanks, Adam. So as you guys can see, it's very, very easy to create a managed object model, drag it into Interface Builder, and start creating your application. And to reiterate Adam's point, this is not a toy application. It looks like it's not a widget that you can't configure. This is doing the heavy lifting for you.

It's taking in the power of Cocoa bindings, the power of the array controllers, the wonderful benefits of Interface Builder, and all the wonderful, wonderful stuff you get from key value coding, and just creating the interface for you. And you can imagine if you spent just a little more time, you could create applications that are actually pretty much fully functional to get you up and running.

I want to cover two common questions that people probably have in their mind about Core Data. I'd like to ask a question first. How many people in the audience think they have lots of data for their application? Lots of data. So the first question on your mind might be, is Core Data fast enough? To answer that question, in our general performance tests, we're able to get about 30,000 objects per second in a fetch request.

Now to put that in perspective, when you think about what does 30,000 things mean, With the exception of the completely enthused in music, that's probably more songs than people have in iTunes. It's probably more addresses than people have in Address Book. And for those people that actually delete mail every now and then, it might actually be more mail messages than people have in Mail. Now, the idea here is not to say that we create applications that work within these particular cases. The idea is that in most of these applications, you're typically not dealing with 30,000 things all at once.

The framework provides you lots of benefits, lots of facilities for going ahead and figuring out exactly what it is you want, either creating a fetch request with a predicate that's very specific to find just the things you want to work with, creating relationships to objects that says, you know, I'm on this recipe. I only want these ingredients. I don't need to fetch them all and filter through them.

Matt Firlik So the idea here is that while we will always continue to improve performance in Core Data, use the other API the framework gives you. Use the smarts that are in your model to keep your working set as lean and mean as possible because you'll get a lot of performance benefit there just by using the framework and the way it was designed to be used.

So the second question is, well, what if I have lots of objects? Is this thing going to require a lot of memory? Because we all know that we all put more memory in our machines than our managers say we should, but our users sometimes don't have as much.

The framework keeps around only the objects that are needed. So as objects are no longer needed, we're going to go ahead and release them. And we grow the graph on demand. What does this mean? It means that as we start to need information, we're going to go ahead and pull it in. So the framework only creates objects when it's absolutely necessary.

So for example, when Adam was going ahead and fetching all the recipes, when the framework brings those back, it actually does something which is create a fault. So it actually hands you the recipe, but to the framework, it looks like a fault. It basically is an unresolved piece of information that says, mm, they're going to want this.

But until they actually ask for it, until they actually do something with it, mm, let's only do a little bit of work. When you ask for information, when you ask the recipe for an attribute, or a relationship, or something interesting, we convert the fault into a real object.

This means that there's one underlying cache for all of your pieces of information. You could fetch the same recipe 40,000 times, and there's only going to be one underlying cache for that recipe. But we try and keep it lean and mean. So we do a lot of work for you to keep your memory footprint low.

So in summary, burn this into your memory. Create a postcard. Make a pillowcase. Do whatever you want. But this is a very, very important thing for Core Data, is the architecture of working with your managed objects, working with a managed object context, creating fetch requests that are important, creating a managed object model-- again, I can't stress enough-- that is really, really tuned for your application and working with the data.

Lots of features, lots of things to provide you to work with your application. The undo and redo support is really, really handy. One of the things Adam didn't demo was we could actually go ahead in this application, make some changes, just hit Control-Z. It's automatically bound up. We're going to back out your changes so you could back out anything and save at any point in time.

You saw the automatic validation, you saw the grouping and filtering, you saw the automatic storing. We didn't have to do anything and it just automatically saved into an XML file for you. Part of that is the template code, admittedly, but there's a lot of things the framework provides for you. And you're going to see a lot of those later on this week. So for more information, take a look at the sample code that's provided by the developer resources.

All right at your fingertips though, already on your Tiger machines are lots of information. Is Malcolm Crawford here? all the way over there, Malcolm Crawford, god on high for technical documentation, writes all the documentation for Core Data. Everyone should give him a round of applause for us having really great documentation.

All of your clapping means that you've all read it, right? Otherwise, you wouldn't know if it's good, so don't be liars. The other thing is there's examples on your CD and actually on your disk. On the disk in developer examples Core Data, outline edit, the tile puzzle, event managers, lots of different samples of data. Also take a look at the Core Recipe samples that we gave you on your CD. You'll see the hands-on stuff tomorrow. Who's coming to the 9 o'clock session tomorrow? Come on. Come on.

You're missing out. It's going to be a fun time. Hands-on session tomorrow, working with Command Line and GUI apps with Core Data. Also take a look at the Core Recipes app. We've done a pretty decent job of documenting everything that's in there. And also look at the migration sample.

I would also-- how many people have used the Quick Model feature in Xcode? Anybody know that it's there? Ooh, very, very few. So as you saw, we actually took a look at the Core Data modeling side. But there's actually a corresponding feature for class modeling, which allows you to select something that builds a class hierarchy and take a look at it in the same modeling construct. To do this, go into your project, go into the Frameworks group, and find the Core Data Framework. Go back up under the Design menu that we saw at the top. Go under Class Model and say Quick Model.

And you'll get an entire class model of the Core Data Framework hierarchy. So you can actually go ahead and look at all the methods, see how they're all implemented. It makes it very easy for navigating the framework. So please use the power of Xcode to help you out with this. And there are tons of sessions and labs for Core Data.

Tomorrow morning at 9:00 is the hands-on. We have two labs tomorrow, one at 12:00 and one at 3:30. There's more Cocoa binding stuff tomorrow. And there's also the Cocoa and Core Data feedback on Friday and the always popular advanced Core Data usages, which is actually going to be really great this year. We've got a lot of really good stuff to show you. Who to contact? Matthew Formica is the Cocoa and Core Data evangelist. But there's also the email lists and everybody I know files bugs. So please use the website.