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

WWDC04 • Session 418

Introduction to Core Data

Application • 1:01:10

This session provides an overview of the new Core Data framework in Cocoa. It will focus on the new functionality provided for managing and persisting model objects, which includes automatic undo/redo, input validation, and saving to various types of "persistent stores" (SQL and XML).

Speakers: Andreas Wendker, James Dempsey, Bill Bumgarner

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 afternoon. Welcome to session 418, Introduction to Core Data. My name is Andreas Wendker, and I'm the senior manager for Core Data and WebObjects. Core Data is a new framework that we added under the Cocoa umbrella, and it continues an initiative we started last year with Cocoa Bindings. That's the initiative to bring you and your applications more functionality for writing significantly less code.

Like bindings, Core Data fills a gap in the Cocoa functionality. Core Data is concerned with fine-grained management of data objects. In this space, it solves a number of very difficult problems, and I actually believe that it will have a much stronger impact on your application development than even Cocoa bindings had.

When I talk about data objects in this session, I really mean the objects that you usually refer to as the "model objects" in the ModelViewController sense. But I'm going to use the term "model" in a different context throughout the session, so I decided to stick with data objects.

Also, I'd like to distinguish Core Data clearly from the new Metadata API, the new Spotlight API. Core Data is about the inside of your data files, about your own applications' documents. Metadata is about the surface, about the outside of those files that you want to export to the file system and to the search API.

So in one single sentence, Core Data is a model-driven object graph management and persistency framework. That's certainly a mouthful, but what does it actually mean? It means that with Core Data, instead of writing a lot of code, you create a description of your data objects. You create a description in Xcode, and that description is called the model of your application. And the model is what's used by Core Data to manage pretty much most aspects of your data objects for you, and it's doing that both in memory and on disk.

That means that you are actually freed up to focus entirely on your application-specific problem domain, instead of having to focus on developing infrastructure for your application. So what can we do with the model? I think the most immediate benefit to many of you will probably be that we can provide you with automatic undo and redo in your applications. So with Core Data, no more worrying about that NSUndoManager.

We also provide you with scalable object lifecycle management. That means that we actually only keep the pieces of your data in memory that is currently needed and we leave the rest on disk, so it scales very well. We will automatically synchronize the user interface. We do that through Cocoa bindings, but we added a few pieces to bindings to make the integration even smoother.

And Core Data also helps you greatly to manage the consistency and correctness of your data. And all you have to do is specify a bunch of rules in the model that tell Core Data how to validate user input and how to maintain relationships or references of your objects to each other.

The other thing we can do is we can automatically read and write your objects to the disk. And we're going to support three different file formats in this first release: SQL databases, XML files, and binary archive files. SQL files are implemented on top of SQLite, which is a very nice, lightweight, embeddable SQL database. It's an open source project.

And SQL databases will usually give you the best scalability if you have large sets of data. And that's the case because with SQL databases we can update your files incrementally. We don't have to write the entire file if just one object changes. Everything is incremental and a lot of the data can stay on the disk. We only fetch them into memory when needed.

XML files have the huge advantage that they are human readable and they are easily consumed by other applications if you need to exchange data, but they won't give you the same performance. One other advantage of XML files is that they are written atomically, so if you are in a typical Cocoa document context where you want to write the files atomically if you save, then XML files are actually a very good fit. Binary files are kind of in the middle, they are probably a good compromise, they don't give you quite the performance of SQL databases and they don't scale to the very large data sets, but they are written atomically and they are reasonably fast.

What's important for this first release is that when you use Core Data, we will take ownership of the file formats, of the file schemas. So on the one hand, that's great because you don't even have to worry about creating tables in your SQL database or creating the schema for XML. On the other hand, you will lose detailed control of your file formats.

To give you some examples of what you could do with Core Data, I actually just looked at my doc and the typical applications I use on a daily basis. And none of these applications, disclaimer, are actually using Core Data right now. We are still building up Core Data. It's really early.

But I think it gives you an idea of what the scope is of things that you can solve with Core Data. So, starting with Safari, the history and bookmark files, that would be a great thing you could do with Core Data. Persons and groups, even the mailbox files within Mail, the music library of iTunes, calendar files in iCal, even sketch documents, which have the different graphics in it, and project files in Xcode. Those are all great candidates for Core Data.

Essentially, every application that manages lots of objects will benefit greatly from using Core Data. The applications that will not see that much of a benefit are applications that work on large blobs of data. So, for example, TextEdit, that works on the RTF or text files, and maybe image processing software won't benefit that much from Core Data.

So why is it good for you? Most importantly, because it relieves you from having to reinvent the wheel again and again and again. Implementing undo and Redo, managing the lifecycle of your objects, input validation, it's all very mundane work that you have to implement for every application, and with Core Data it's done for you. You save a lot of time, you will have a much faster development cycle.

Core Data also will give you robustness and flexibility. The choice of different types of data stores with the different characteristics and scalability and human readability, etc. I think will turn out very handy for many of your applications. And also very important, Core Data will prepare you well for the future for features you might add in Cocoa.

Now that we have a model, we can interpret that model in many different ways without you writing any line of code. So you could envision us to, for example, add Apple Scriptability to your applications, or maybe automatic rendezvous connectivity. So there are some features we are looking at in the future that I think you will be able to pick up automatically if you start using Core Data soon.

These are actually fine-wet screenshots from an actual application we converted over to Core Data recently. And that application was already using Cocoa bindings, so there was no glue code for the UI layer. And as you can see, we were still able to shave off a lot of the code. And by the way, this application now has more features than it had before. For example, now it has undo and redo. So with that, I would like to ask James Dempsey to come up on stage and give you a first demo of Core Data.

Thank you, Andreas. So what we're taking a look at here is an XML document as might be managed by Core Data. We're going to put that away for now. We're going to jump right in and build a full-featured, document-based application with zero lines of code using Core Data. We're going to use the Core Data Document-Based Application Project. Call that thing.

Demo 1. And with Cocoa bindings, you essentially had your data objects able to be synchronized with user interface objects through bindings, but you still had to manage those data objects yourself. With Core Data, it's kind of like the other half of the equation, where those data objects, you can model them, Core Data will help you manage them, and also deal with the persistence. So let's take a little look at the project.

and the code that's in there. If we take a look at the classes, we have a document class, which is a subclass of NSPersistentDocument, which in turn is a subclass of NSDocument, and this subclass adds all of the hooks needed to interoperate with Core Data, including persistence. Let's take a look at the implementation file, and you'll notice a couple of common NSDocument methods here, and a few that are missing, ostensibly those that are for writing and reading data.

So, we don't need these initialization items either. So, in essence, this is a negative lines of code demo. We'll next look at a new resource in the project: the model. A little later in the session, you're going to see how you can create a model from scratch, but to save time, we're going to import that XML file that I showed you earlier.

and Xcode is going to build an entity relationship diagram based on the structure of that XML file. And if we take a look, we have persons, events, tasks, an event management sort of model. So now we have our model, let's build our user interface. We'll head into our document nib file. Get rid of this.

And what we're going to do is option drag, in this case the person entity, let me pick it up here, into interface builder. Interface builder is going to ask us whether we want a user interface for one object handled by an object controller or many objects handled by an array controller.

We're going to deal with many objects in this case. And you'll notice that a user interface has been built based on the properties of the person in the model. And in addition, an array controller has been added to the project. Let's just take a look at the bindings of this text field here.

Take a look at the value. And you'll notice that it's hooked up to the array controller selection for the model key path first name. It's just a straight standard Cocoa binding. In fact, all of the user interface is dealing with Cocoa bindings in that array controller in the way it has in Panther.

So what's the new stuff? Well, if we take a look at the array controller, you'll notice a couple of additional features designed to integrate Cocoa bindings with core data. The first is instead of naming a concrete class, we have the choice to pick an entity, in this case a person, so that the array controller knows what type of thing it's dealing with.

If we look at the bindings of the array controller, you'll notice a new binding called "managed object context." And the managed object context, Andreas will be talking about it later, but in essence, it's the object that's providing and doing a lot of the heavy lifting for the functionality that we're going to see in a moment when I build this application.

So, one entity is kind of useful, but very few applications deal with one kind of object and one kind of object alone. Core Data is actually very good at dealing with relationships between types of objects. So, a person is related to many tasks. Let's get a user interface for a task, many tasks in fact.

Let's clean this up a little. Again, these are just plain old IB things, so we can get rid of them if we want to. Let's get that task field a little bigger so we can read it, get rid of some stuff. Okay. Now let's take a look at that task array controller. We do need to bind its content so it knows where it's getting its tasks from. We're going to bind that content to the person array, its selection, and within that selection, the tasks of the selected person.

Let's save our change and let's build our happy little application here. While that's building, let's just take a look at the types of documents that we can save to. Predefined is the binary archive format, the SQLite document format, as well as the XML format. So our build has succeeded. Let's run.

Hide a bunch of stuff. And here's our application. Let's open up that XML file that we had seen earlier. And you'll notice that indeed as I jump through the items in this table view, everything's updating. I'm seeing all of the tasks that are related. It looks like Andreas has the most to do out of everybody.

We have all the common Cocoa bindings, sorts of features such as sorting, such as multiple selection, and some new goodies such as filtering. So if I type in some filtering there, it will filter for me. And the UI has automatically built in a menu so I can pick particular things that I want to filter upon. Now let's jump on over to our new document and add some people. Let's add Bob Jones, let's add Barry Bonds, and let's save.

So I'm going to save, again these file formats appear here. Let's do the SQL thing, call that test, we'll save it. And on our desktop is that SQLite document which represents the SQL database. And let's close the doc. Now let's open it up again, thus proving beyond a shadow of a doubt that it persisted. And there it is. I think I forgot to type in "bonds". There we go. So let's make it persist, eh? There we go.

What did I do? I may have disconnected that text field in Interface Builder. My apologies. Okay, with that, let's add a new person. Betty Brandt, and let's change Bob to Robert. and let's remove Barry for legal reasons. Now, you'll notice looking at the document that the window does know a change has occurred. It is dirty and if we go to the edit menu we do have undo. So let's undo through this. We should get Barry back, Robert should get back to Bob, and Betty should disappear, and of course redo. And if we... Feel free.

And if we quit, of course, it knows the dock is dirty in Alaska if we want to save. We don't want to save. Okay. Let me close up this project. I'd like to show you one more thing beyond that codeless demo, which is that that's a very Cocoa-centric demo. This application here, the three bears, is a Carbon application that's using Core Data underneath for its persistence. And in fact, this is the XML file that it's writing to. Let me just open that up in TextEdit.

And so, we'll add the baby bear whose height is very small. We'll save and quit and restart, and indeed it has persisted. And then if we get the saved version from disk, you'll notice that that XML document has updated. So, let's take a look at the project. and it's in Objective C++ and it's the code here that is doing a bit of transition between those Objective C objects from Core Data and Core Foundation types that Carbon would be able to use. And so, depending on which flavor you wish, you can use Core Data with both. So thank you very much and now back to Andreas.

Thank you, James. Now let's talk about models. Models are high-level description of your data objects. They're essentially entity relationship diagrams of your objects. And the model is what's needed by Core Data to implement all these nice features like Android Redo and ultimately read and write your data objects to disk. In fact, the model is all that Core Data needs. As you saw in the demos before, there was no additional code really necessary to do all this work.

One thing that's important, though, for you to keep in mind is that you and your models, you would have to spend quality time together. The models need to be very detailed for us to do a good job, so the more detailed you make your models, the better of a job Core Data can do.

One thing that's interesting in this context is that we decided to separate the five formats for the models you edit in Xcode and the models you load at runtime. The reason for that is that Xcode manages additional information that you don't need at runtime, like the layout information of your diagram and maybe the colors you chose for the different boxes. And we didn't want to burden the runtime with that. So while your project is building, you're actually translating the model as it is written in Xcode and managed in Xcode into a new file format that is then imported at runtime.

Models essentially consist of two pieces: entities and properties. Entities describe the types of objects, and properties describe the individual object components, the values inside those objects. For each entity, you can specify a class name that is used to represent that entity at runtime. And specifying the class name here will turn out to be the most important hook for you to plug in your own application logic.

Another thing that's interesting about entities is that they can be organized in a hierarchy, which is actually independent of the class hierarchy you use. So, for example, if you have a person entity, you might have sub-entities like employee and customer. and you can then map those entities to either a class hierarchy that is the same or to classes that have nothing to do with each other, or you can even map those three entities to the same object class at runtime. That's actually fairly common.

The advantage for you to use entity inheritance that you model the types of data is that you can, for example, define your queries on the abstract entity. You can still search for all persons and then get back customers and employees. So there's a lot of flexibility for you when you work with your data objects.

For properties, we support three different types: attributes, relationships, and fetch properties. Attributes represent the simple types of data in your object, like strings, numbers, dates, and maybe binary data like images. And relationships represent references of objects to each other, and they'll be distinguished between "to one" and "to many" relationships. A "to one" relationship is simply a pointer, a reference to another object. A "to many" relationship is a collection of references to other objects.

In this first release, we're going to support only unordered relationships, and the natural representation for that is actually an NSSet. Going forward, we're probably going to add support for ordered relationships too, and those will be represented by NSArrays. For NSArrays, we will then also archive the order of the object in that array in the data stores.

Relations typically come in pairs. If you have a person that points to a company, there's usually also a pointer back from the company to the person. Those relationships are called inverse relationships, and they make your object graph very rich, actually. It makes it much easier to navigate through your object graph. So we recommend that you typically enter the inverse relationships in your model, too.

Fetch properties are similar to relationships, but they are much more loosely bound. You can think of them as smart groups. To make it more concrete for you, in an SQL database, a relationship will actually result in a join that is enforced in the database. A fetch property is much more of a loose query.

So for all these properties, the model contains a wealth of information, starting with validation rules. Those are the kind of mechanical validation rules, like the length of a string, or maybe the value of the expression a string has to match, min and max values for numbers and dates, those kind of things.

There are also delete rules for relationships, and those delete rules tell Core Data what to do if an object is removed from your object graph. Typically, there's something like a ripple effect if you remove an object. Let's say you have a person object which has addresses and contact information. If you delete that person, you want to get rid of the other information too.

And delete rules allow you to specify that kind of behavior. And there are different choices. You can kind of cascade the delete, so that's the ripple effect. You can deny a delete, depending on the situation. So there's a lot of flexibility in these delete rules. And also for attributes, we store default values.

Those are simply the values assigned to your object when they are inserted. So, this table summarizes the kind of mapping we do at runtime. An entity essentially maps to a class, an attribute maps to a simple instance variable, and a relationship maps to a managed reference or collection of these references. They are pointers.

There are some more things in the model that I want to go over quickly. Startinging with predefined queries, you can enter pretty much templates for the common queries you want to do, you want to perform in your application. Again, something like a smart group would be a good example here. Typically, you would specify variable names within those queries and then substitute concrete values at runtime. So those are very handy and it's actually a huge convenience for you to specify those queries in the model upfront.

There are also some that we call "configurations" in the model. A configuration is pretty much a named group of entities, and those configurations are used in the more advanced cases when you talk to multiple data files at the same time. Each configuration then maps to one data file, and you can pretty much predefine the mapping to the different data files in the model by separating those configurations and naming them.

The last thing I want to mention is that we also decided to give you some flexibility to customize the model. We added so-called "user info dictionaries" to entities and properties. You can store your own information in there. These are pretty much arbitrary key value pairs you can enter in the modeling tool. The typical use case for that is actually localization.

So with that, I'd like to ask Bill Bumgarner to come up on stage. There he is. And he will give you a more detailed demo of the model.

[Transcript missing]

You'll see that this arrow right here updated. That's because, of course, the arrows indicate the ordinality of the relationship.

Relationships are allowed to have ordinality so that you can say a car can only have four tires, that kind of thing. And upon save and upon manipulating the objects at runtime, the system will validate that. Andreas will be getting into that in more detail. Now, there's some other...we've learned a lot about modeling tools. We, as some of you might know, we've done some things wrong in the past and... Hopefully you'll find this to be a refreshing change.

So one of those is that it was tedious and annoying to have to go through a model and edit a particular part of an attribute over and over and over again. So what you can actually do is you can come in here and you can multiple select in here and you'll see that the inspectors over here update to only show you the items that are relevant to those things.

I can come in here and I can select first name and last name, and I can change the validation rules for both of those at the same time. But of course, often times when you're modeling stuff, you'll have attributes across many entities that will need to be changed at the same time. So I can come in here and select them all, and then I can sort by entity, or I can sort by property or kind, and then I can again select multiple across multiple entities and edit them all at once.

We also have the fetched request editor. So if I come in here, I can build a new fetch request, and I can then actually edit the predicate, and we give you a graphical predicate editor. So we can come into here, and let's say, we will say this is confirmed, yes, and we also want to make sure that the date is, well, less than, you know, and we can say maybe we want to add an "or" here, so we can say the date is greater than

[Transcript missing]

If I wanted to say, "Oh, well, this really should be at the top level," I can just drag it up there, and it'll restructure itself appropriately. And then of course, as Andreas mentioned, there is the user info here. So it's just key value pairs. So we allow you to annotate your models with whatever you need. Thank you.

And then of course, as Andreas mentioned, there is the user info here. So it's just key value pairs. So we allow you to annotate your models with whatever you need. Thank you. As I mentioned before, the most important hook for you for that is to specify your own data object classes in the model.

One requirement we have with Core Data is that we require you to subclass a new class that we call NSManagedObject. NSManagedObject actually is a generic data object, so you can use it with an arbitrary entity in your model. That's what we did with the demos so far. There were no custom data object classes in there, so we just used the NSManagedObject.

It's not doing very smart things, such as storing, getting, and setting values, and it's performing the validation rules. But for your own custom logic, you will subclass that and then add your own specific code for your problem domain inside those subclasses. That said, NSManagedObjects are probably sufficient for many cases. If you don't need anything special, just stick with NSManagedObject. It's much more convenient.

When you subclass, you typically implement your own logic in the normal setters and getters that are defined with QValue coding, the naming schemes we defined with QValue coding observing. The same is true for validation, and we also added a bunch of hooks notifications for you in your objects where you have methods that you can override to react to different kind of state changes. And I'd actually like to walk you now through most of the API of NSManagedObject.

The init method takes two arguments. First of all, the entity that the object actually represents. The second argument is this NSManagedObjectContext. James already referred to it a little bit in his demo. And the ManagedObjectContext is the object that does all the work for you. It triggers the undo and redo, it triggers the validation. Every managed object obviously needs to be assigned to a ManagedObjectContext. The first thing you should do if you create a new object is insert it into a ManagedObjectContext.

There's a get method for it, and there's also a method to get the entity of the object. And getting the entity can be very handy at runtime if you want to do some introspection. It's actually very similar to using the class information stored in the Objective-C runtime. You can use the entity to get more information of your objects: what properties are there, what attributes, what relationships are there, to what other entities can you navigate from a given object, those kind of things.

Managed objects also have an object ID. The object ID is pretty much a unique reference that is created when your object is stored in the file system, and it's guaranteed to stay the same throughout the lifetime of that object. So if you ever need to get a hold of an object and then store it away and get back to it later, that object ID is a good reference for you to use.

To react to state changes, there are a bunch of methods you can override. First of all, there are some get methods. The method just is inserted, is updated, is deleted. They just tell you about the state of the object. They are very handy in the context of bindings. For example, you can wire up the enabled binding of a text field to one of these methods if you only want it to be editable in certain situations.

There are methods that inform you if the object was just fetched or inserted. Typically, you initialize your own caches in those methods. And there are methods that tell you that an object is about to be deleted or saved. And here you can typically set some values, maybe a timestamp right before it's saved, something like that.

For key-value coding and observing, we just follow the normal standards. The generic methods are valueForKey and setValueForKey. You typically don't override those methods directly, but instead you implement your own accessors. Those generic methods call out into custom versions of the key-value coding methods like setName and name to get the name property.

One thing that's new in this release is that we also added support for set mutators if you want to modify too many relationships since they are all represented by sets in this release. They work the same way as the array mutators worked in the last release. You pretty much get a hold of a mutable set for a given key and then you modify that set and that modifies the relationship indirectly.

There are two more things that are interesting in the context of key-value coding and observing with managed objects. Number one is that you typically still want to access the generic data storage mechanism of managed objects. You don't need to add your own IVARs to store your values. You can continue to use the generic mechanism.

And actually we recommend that you do that because you can optimize the access to the values much better if you continue using that generic storage mechanism. So to access the values, we added the primitive key-value coding methods: primitive_value_for_key and set_primitive_value_for_key. And again, you use them in your own custom accesses like set_name and name to call out into the generic storage mechanism.

And then the accesses need to be wrapped by "will change" and "did change" methods and also now "will access" and "did access" methods and the "read" methods. Key-value observing actually has this really nice behavior to do this automatically for you. We don't have that implemented for NSObject yet.

We hope to have that ready by the end of the release when we ship. But at this time you will have to explicitly call "will change" and "did change" in your "set" methods and "will access" and "did access" in your "get" methods. So this would be an example.

For example, if you have a social security number property, the "set" method would jump out in the first call "will change" then access the "set primitive value" for "key" and then call the "did change" method. The "get" method would first call "will access" then "primitive value" for "key" and then "did access". And of course you can insert your own code in between here if you want to do your own customizations.

For validation, it's very similar. The generic method is validate_value for key error. Again, you typically don't overwrite that directly. Instead, you implement those custom methods we call, something like validate_name error. And there are additional methods for the state changes where you can validate the state changes. So, validate_for_delete, insert_and_update, you can deny a delete, for example.

Those would be two concrete examples. Again, that's a social security number. First check whether the value is actually of a valid type, and then maybe check the length, and if it's not the right one, you can create an error. And also you can deny an insert. You can pretty much intercept a save and deny that save if the social security number isn't set yet.

So let's look at the architecture of Core Data and what actually happens to your managed objects. What we already heard is that the managed objects are always assigned to a managed object context. That's the object that has most of the work for you. To the UI side, the managed object context is simply hooked up, usually through Cocoa bindings to the UI. You don't have to use bindings. We saw an example with the Carbon UI, for example.

But it's the most convenient way to handle managed objects. So you simply hook up a Cocoa bindings controller to the managed object context. It will then go and filter the objects out that need to be displayed in the UI. It will sort them, prepare them for the UI, and then populate the user interface.

To the other side, to the persistent side, Managed Object Context is hooked up to Persistent Store Coordinator. That coordinator is the one that provides the model, so it tells the Managed Object Context what types of entities are available. And it's also the object that synchronizes the access to the different data files of your application.

Let's take a step back and summarize quickly. The managed object context is the center of your new world. It's really the thing that manages everything for you. It does undo and redo, it triggers validation, maintains the inverse relationships that I mentioned before. All that work happens in the managed object context.

It serves as the gateway to the persistent store coordinator. If you want an analogy for it, it's something like a scratch pad. It allows you to load objects into memory from your external files, then modify them, and then either save them back to the file system or just throw the changes away if you don't need them anymore.

Persistent Store Coordinator is the instance that provides the model. It synchronizes the access to the persistent stores. And the idea really is that if you use multiple stores, multiple files at the same time, it represents something like a unit of them. So it merges the content of all the files together.

And to the managed object context, it just looks like it's talking to one single data source. What's important here for this first release is that we only support striping in this first release. So you can merge the content of different data files together in one context, but we don't support mirroring.

I want to talk a little more about memory management. I'd already mentioned that we We will give you good scalability by only keeping the pieces of your object graph in memory that are actually needed. Needed means that the objects are either changed or they are currently displayed by the UI or referenced by any other part of your application.

Core Data will make sure that your object graph grows on demand if you go deeper into your object graph. One concept I want to mention here is the concept of faulting. Most of the time, let's go back to the example that we had before, the XML file that we showed in the beginning, you have an event management system. It's common that you look at a table of data objects, but if you drill down, it's uncommon that you actually take a look at all the objects in your data file. So, we will make sure that we only fetch those objects into memory that are needed.

But you as the developer, you shouldn't have to worry about whether an object has actually been fetched into memory, whether it has been fully initialized or not. And so the concept that we use here is a concept of little placeholder objects. Essentially, when you fetch an object into memory, it's surrounded by little placeholders that we call faults. And those faults are not fully initialized, so we haven't done the work to actually go to the persistent store and get the data from it, so it saves a lot of time and memory there.

But the placeholder object is a valid reference. So let's say you have that event object that has tasks assigned to it. The task objects can be referenced. Those placeholders are valid references. You don't have to worry about whether those are fully initialized or not. And we do this pretty much automatically for you. The good thing for you is that you don't have to worry about whether the object has been fetched into memory or not. For you, it's completely transparent.

In a typical document-based application, you will use multiple stacks of Core Data in parallel, stacks that are completely isolated. So each document will typically have its own managed object context, its own persistent store coordinator, and will typically talk to a single document. In a non-document-based application, you usually have multiple stores that you want to combine.

You might have a store in the user's home directory, some additional ones in the network, and maybe you even have removable media that contain additional data files, additional stores. So then again, the persistent store coordinator manages the access to all these files at the same time, and it presents a unit of the stores to the managed object context.

Let's take a look at what happens if you actually fetch objects, if you load objects into memory. Typically, a request is triggered by the UI layer. For example, a Nib file is loaded that contains a controller. That controller is hooked up to a managed object context, and when it's trying to populate the UI, it submits what we call a fetch request to the managed object context.

So it's going down the stack. The managed object context will forward that request to the persistent store coordinator, which will take a look at the model and then decide what kind of data file it needs to access. It will load the objects from the data files and send the data to the managed object context, which will then materialize that object graph.

And then the controller... We'll filter out which ones actually need to be displayed in the UI, we'll sort and prepare them, and then populate the user interface. And then over time, when you fetch more objects, if you have maybe loaded additional Nib files, or if you look at different master/detail relationships, the object graph will simply grow over time.

When changes happen, those changes usually start in the UI, the user goes into the text field and enters a new value. With the help of the controller, it will then access the data objects. and we'll start applying new values to the data objects. And that in turn will cause a key value observing notification to be sent out, so the managed object context will be notified of the changes in the object graph.

And it will then start tracking the changes, it will start undo and redo, managing the undo manager, all these things. Essentially, managed object context will observe all the changes to your object graph over time. So if additional objects change, it will simply track all that. If objects are inserted, if objects are deleted, it will keep track of all these changes.

And then when you save, that request usually again starts in the UI, it ends up on the managed object context, and the managed object context will then package up all the changes, all the deltas to your object graph, send them to the persistent store coordinator, which will again take a look at the model to find out which data files the changes have to go, it will update the data files for you, and then on success, it will notify the managed object context, which will reset the object graph to a clean state, and then everything starts from the beginning.

I'd like to introduce you to one more concept that is very fundamental to Core Data, and that's the concept of predicates. Predicates define filters. They're used for queries. And typically, you either pre-define them in the model, you use substitution variables for which you can then substitute the concrete values at runtime, or you create them programmatically, which is usually based on the user input, for example, in a search field.

You can evaluate predicates both in memory, if you already have objects fetched, you can filter them out in memory. And sometimes we decide to translate a predicate into another query language. In the context of SQL, we want to make use of the capabilities of the SQL database, which can do the queries very optimised and very fast. So we will translate those predicates into SQL and perform the fetch there. NSPredicates, the classes that represent predicates, are also used outside of the Core Data context. The new metadata API in Cocoa uses predicates. We also use it to implement filtering in the NSArrayController.

These are some examples for predicates you can write. It starts with simple comparisons like "name = Tom". We support case and diacritic insensitive lookups. "Contains" is the operator, and then you can have an additional flag, the "C" for case insensitive and the "D" for diacritic insensitive. We support logical operations, "and", "or", and "not". We allow you to look into relationships.

For one relationship, you simply just follow a key path, like "group.name". For too many relationships, we give you additional operators, like "all" and "any". So you can look up persons for which all children are older than 12, or just some of them. and we even support things like simple operations like computing the sum of all the prices of some items in a list. So as you can see, there's a lot of flexibility here in Predicates to define the types of queries you want to perform on your data objects.

At runtime, predicates are represented as a tree of NSPredicate objects. There are three classes you will encounter. NSPredicate is the abstract superclass. NSCompoundPredicate is the class that represents logical gates like AND, OR, NOT. And NSComparisonPredicate is the predicate that performs all the different operators, the different comparisons like less than, greater than, contains, matches. There's a list of operators we support.

Comparison predicates use NSExpression objects to provide the actual computation values. There are different types of expressions. Again, there are expressions for constant values, expressions that follow key paths. Again, there's a list of different types of expressions we support. What I think is really important for you is that the predicate architecture is extensible.

So you're not limited to the data types we support. If you want to define special operators that work on NSColors or on NSImages, you're free to do so with the predicate architecture. And now I think we have another demo for you. And Bill is going to just show you some predicates in action. - Okay.

So I'm first going to show you just briefly a little application that I use to pull a bunch of data. And mostly I just wanted to show the model briefly because this will be the model that will be used for the other demos. This is actually an application that will go out to Amazon through their public API and will pull a bunch of information about books you search for, and then will populate a core data database.

So if I wanted to, I could go out and say, you know, search for everything with Cocoa in it, and it's going out making a WSDL-based web services SOAP call to Amazon, pulling the data back, throwing it in a core data data store, and then throwing it up in our default user interface, including cover art.

So that's just a simple little app, a few lines of code. So that's our data model there. What we're going to be looking at is products and manufacturers. Amazon uses manufacturers because they make more than -- or they sell more than books. So think of them as publishers. Okay.

So let me close that down and go to Booklist. So I decided I wanted a little application that I could use to grab a bunch of books from Amazon and start building up my wish list. So I wrote a little app and let me go ahead and open some data.

book data. As you can see, I get a big list of books and their prices and et cetera. And now I can apply some predicates to it. So the first predicate I'm going to apply is just a very simple one. I want to find all the books or all of the entities of type product that have the product name contains the word "coco." So you can see it's executed, and there it is.

Now, predicates can also do some more complex things, like I can say, "Show me all of the books at Amazon where the price is between $15 and $25." As well, since predicates are all based on key value coding, and it should be emphasized that they aren't limited to just managed objects. They will work with any object in the system that's key value coding compliant. I can also follow key value paths.

So in this case, I'm going to ask all of my products for all of their manufacturers and then ask for all manufacturer names that begin with O'Reilly. So as you can see there, it's actually following the key paths. So I'm going to say, "I'm looking for O'Reilly," and I get my list of books from O'Reilly.

Now, I can also do things where I'm testing if one object is in a set of objects that are related to another set of objects. So in this case, if I want to go in and find everything on Microsoft Press and McGraw-Hill and Addison Wesley and Sam's, I can do that. Now I should actually show you a little bit of code here. This is a simple little application. To apply the predicate in the first place, that's not it. There it is. This is the line of code. Oh, I should scroll a little bit.

These are the two lines of code necessary to create a predicate and apply it to an array. The first line will actually take that string that you saw in the user interface, those were actual real live predicate expressions. It will evaluate it, turn it into a predicate object, which you can then programmatically query or take apart if you want to. And then it will apply it to an array and return the array of objects that result from it. There's also a mutable array version of this, so you can take a mutable array full of objects and reduce it by whatever objects pass the predicate.

The second example also shows how to do custom predicates. So in the case of this user interface, I needed to basically check to see if a particular product has a manufacturer of this set of manufacturers I have selected in this UI. And in that case, in this line of code, I'm actually creating a comparison predicate and comparison predicates always have a left expression and a right expression.

So in this case I'm saying the left expression is the evaluated object and all that means is that it's the object in the array of books that I'm trying to filter. It's the thing I want to filter. And the right expression in this case is a constant value and it's my selected manufacturers. It's just whatever I have selected in here.

And in this case I said I want to use a custom selector, which is member of array. And this is going to be a method that's going to be invoked on objects from the left hand side and it will take an argument from the right hand side will be the argument passed to it.

So in a category on NSManagedObject, because in this demo we're using nothing but managed objects, I wrote the member of array method, which as you can see is pretty straightforward. So using this, leveraging this, you could, like Andrea said, you could qualify anything. You could predicate any object as long as you have key values in it. So you could have a method that takes a single argument and returns a Boolean.

Now if you get into expressions, which are more complex, then you could open it up even further. Now I have one more demo. We at Apple like to eat our own dog food. So this is actually the core data predicates are being used by metadata in the Objective-C API to metadata.

Let me go ahead and run this application. And it comes up and it gives you a field and you can type a query into it, which is going to be a metadata query. And it will show a list of files that result. So, for example, I can ask it, "Show me all files Let's start with the word "app delegate" in their file name. It takes a second, but there it comes. You can see that the results are filling in as it goes. This is again because it's all leveraging key value observing and key value binding.

We can do some more complex queries, like for example, I have a metadata importer that grabs Objective-C metadata from Objective-C source files. In this case, I'm going to find all files on my hard drive that implement subclasses of NSView, which is pretty handy if you want to find stuff in example code. Now, let's look at the code. The code for this is actually quite straightforward.

and you can ignore the notification center stuff. That's an unfortunate hack necessary to make the demo work right now. It goes away. It doesn't exist. Those lines are not there. So we simply create a query and then we set the predicate on the query and again you see that line of code. Predicate will format argument array. And that's it. Start the query, you're done. So those are predicates.

[Transcript missing]

Of course, the seat you have in your own hands right now is a very early bit, so not everything is fully working right now. SQLite, you already saw it working here on stage, but the access for you in the seat is not available right now. The other two things worth mentioning is that controllers aren't as live as we'd like them to be right now. We'd like them to react much better to adding and removing persistent stores on the fly, and then update the UI automatically. We don't have all that implemented yet, and also fetch properties aren't supported at this time.

Then of course, the little things like localization, better error messages, leaks optimizations, that all is still forthcoming. That said, the complete API can be completely exercised with the XML store that actually works fully in the seat that we have. So we would like you to... So, please try it out. We would like to get your feedback. You can send an email to [email protected] or you can submit bug reports. Actually, submitting bug reports is probably the best way for you to communicate feature requests and ideas and also the bugs you encounter. Thank you.

So in summary, Core Data is a model-driven framework. It manages your objects. It persists your objects. It automatically updates your UI to Cocoa bindings. It solves some very difficult problems like undo and redo. It gives you great scalability. It gives you choice in persistent stores. We support SQL databases, XML files, and binary files.

We have added some good support in Xcode for modeling. There's a great modeling tool for you. And really the benefit for you is that you will write a lot or significantly less code. You'll be a lot faster while you develop your application. So that was my summary. The good news for you is that there's going to be a second summary.

So last year we had a little song to go with Cocoa Bindings called Model View Controller. And this year, with the focus on Core Data and building some data models, since the songwriting tends to go where the technology leads me, it's a little song about data modeling. So we need to switch over to the laptop. Excellent. So hope you like it.

They say, "Are you in modeling?" I say, "Oh yes I am." There's no catwalk involved in the modeling I do. There's no demand for me to try that kind of modeling too. Some people want a data model for a new application, don't want to write a lot of code, simply use configuration to refine your data model with each new iteration as you build a prototype with persistence automation.

Some people want to date a model but prefer one in fashion If you date a data model that's an interest and passion You're a dreamer with a schema you can usually cash in Though you ain't got the looks in your clothes they are clashing Modeling man, I'm a modeling man Let me lay it all out so that you'll understand You'll have the terminology and concepts at your command ♪ So you can also be a modeling woman or man ♪ You design your data model as pretty as you please by adding items to the model known as entities. And entities are right by me.

It's what a thing's supposed to be. What type, what sort, what class, what kind, whatever you might have in mind. You pick a name, map to a class. Now your model's growing fast. You work some more and come to grips with attributes and relationships. You design your data model as pretty as you please by adding items to the model known as entities. And entities are right by me. It's what a thing's supposed to be.

What type, what sort, what class, what kind, whatever you might have in mind. You pick a name, map to a class. Now your model's growing fast. You work some more and come to grips with attributes and relationships. Now your model's growing fast. You work some more and come to grips with attributes and relationships. Now baby, now you're modeling too.

I said, "Baby, what more for a mildly man to do?"

[Transcript missing]

I said I'm a modeling man, I'm a modeling man. They say, "Are you in modeling?" I say, "Oh yes I am." There's no photographers involved in the modeling I do. I got turned down by everyone I gave my headshot to.

[Transcript missing]

The entities can be connected, kinda joined at the hip. The formal name for this arrangement is a relationship. One object references the other, so it can't give it the slip. The inverse reference is maintained for a convenient round trip. I said, I said, "I'm a modeling man, yeah, I'm a modeling man." They say, "Are you in modeling?" I say, "Oh, yes, I am." But don't come knocking if it's rocking in the back of the van. I'm probably wrestling with relationships I don't quite understand.

[Transcript missing]

I have the boring task to finish up the session, if you could switch back to the slides. There are a few more sessions I'd like to point you to that are related to Core Data. Using and customizing Cocoa bindings this afternoon at 5:00, we'll have a little piece on the UI part of Core Data. Tomorrow morning at 10:30, there's advanced Core Data. And on Friday morning at 9:00, we have an overview of the modeling tool in depth, modeling and design in Xcode. These are the usual people to contact.