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: wwdc2009-114
$eventId
ID of event: wwdc2009
$eventContentId
ID of session without event part: 114
$eventShortId
Shortened ID of event: wwdc09
$year
Year of session: 2009
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2009] [Session 114] What's New ...

WWDC09 • Session 114

What's New in Core Data

iPhone • 44:59

Both Mac and iPhone developers now have the power of Core Data at their disposal. See what's new in Core Data for both iPhone OS 3.0 and Snow Leopard. Learn the most efficient ways to employ Core Data in your next project while taking advantage of recommended design patterns. Walk through solutions to the most common problems facing experienced Core Data programmers.

Speakers: Adam Swift, Melissa Turner

Unlisted on Apple Developer site

Downloads from Apple

SD Video (103.9 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

I'm Adam Swift, I'm an Engineer in the Core Data Team and I want to talk to you about the new features in Core Data and Snow Leopard. Now I was joking that I was going to come out here and just say "It is on the phone," which is great and we're really excited about that.

But really we've got a lot of new features in Snow Leopard that we think are going to help you accelerate your development, optimize your performance, and really get the most out of Core Data in your application. So in this session, we're going to talk about data migration, Spotlight integration, best practices for using Core Data with Grand Central Dispatch fetch performance and a variety of tips and tricks.

So at the end of the session, what I'm hoping you'll walk away with is an understanding of how to take advantage of these new features, to reduce and simply the amount of code you need to maintain, and improve your performance to use less memory with Core Data and achieve faster performance. So the first thing I'd like to go through is lightweight migration. And the general philosophy here is you start out with an application.

And when you're first doing your data model design, you think about the needs of your application, you design your entities, the attributes, to store all the data that you need, and you have some considerations for performance. But as soon-- as soon as you start building an application and testing it, you realize that as your data set grows, there are some places where your performance starts to suffer.

And also, when users start to get access to your application, you are going to get some feedback about missing features or some other things you'd like to change. And this is the right time to start thinking about changing your data model to adjust for what these changes are going to require. And we want you to do that, this is the right time to be changing your data model.

So in Leopard, we introduced scheme and migration and I want to walk you through that process really quickly just to review. So you start out with the version 1.0 of your data model and you build up some data and you can see that in the store file there, that's the box with blocks in it.

And when you realize, you need to change your data model, you can build a mapping model to describe those data transformations to convert the data that you've got in version 1.0 of your data model to the version that's compatible with version 1.1 or 2 or whatever it is. So you create a map on migration manager and you set the mapping model on the migration manager, feed in your source data store and out the other side comes a data store that's compatible with the next version of your data model.

And that's the Leopard schema and migration process. And let's look through the basic steps or the basic rules of Leopard schema migration. You need a compatible data model to open-- to access your data And you can create a mapping model to migrate that data. Now Xcode provides an assistant, but creating a mapping model does require a little bit of hand tuning and if you have truly complex changes in your data model between versions, you'll need to write some code to deal with those transformations.

And all of these things are described in the Core Data Model Versioning And Data Migration Programming Guide. So if you haven't worked with a mapping model before, I want to show you what it looks like and this is the standard Xcode editor for a mapping model. And you create it in the assistant with a source data model and a destination data model. And then for each of the entities in your data models, you need to provide entity mappings. You need to define entity mappings to describe each of the properties of those entities and how they should be transformed from version 1 to version 2.

And during the development process, you're going to repeat the cycle over and over again as you test, change your code, change your model, you'll discover new performance bottlenecks, or you may find more features you want to add. And this change is good and we wanted to facilitate this is much as possible.

So this is one of the things we focus on for Snow Leopard was adding a new automatic migration technology we call "lightweight migration." And it's simple data migration, it's easy to set up, and you can do it with zero code. We think this is a huge win and really encourage everyone to try it out.

So what is it? It's inferred data migration. Core Data will automatically infer the mapping model for you. It only handles unambiguous changes but that covers a lot of territory. So I'm going to walk you through a few examples of what is considered unambiguous or inferable changes. So in version 1 of your data model, you have defined a song entity, and it has an attribute, name attribute and album and lyrics relationships. Well, when you go to make an update your data model, you want to make some changes. You decide that name really isn't expressing the right-- the song title the right way, it better expresses this title.

So you replace name with title and your users are saying they want to know-- they want to keep track of how long the songs are. They want to be able to see that in the interface. So you can add a length attribute to your song entity. Also, you got feedback that nobody is really interested in keeping track of the lyrics and really it's just causing your performance to get bogged down.

So you get rid of that relationship entirely. All of these changes can be inferred automatically and the data can be migrated with lightweight migration without any code. So let's look at another example. You can add, remove, or rename entities as well. So going back to the data model, you've got, say in version 1 you've named your entity-- two other entities, musician and lyrics. Well, you just got rid off the lyrics relationship so you might as well get rid of the entity entirely.

And you can do that. Musician really isn't expressing that entity name correctly, it could be better called artist. And maybe you are starting to build a relationship with some of the record labels so you want to be able to represent that in your application as well. So you can add the label entity and create a relationship from your artist to label. Again, these are all inferable changes and the data can be migrated without any code. Let's take a deeper look at what kinds of changes you can make with your entities in lightweight migration.

So in version 1, we've got a song and a video and they share a lot of the same properties. They both have name attributes and they both have data relationships. But you can't have a relationship that goes to either one of them, to both-- you can't have a relationship that goes to objects of both of those types because they don't share a common parent. Well, you can add a common parent and have that-- have both of those entities inherit from it and even move those properties up to the parent entity.

And this again, can be handled with lightweight migration. So how do you do it? What do you need to do to use it? It's got really easy set up, there are just two things you need to do. One, you need to keep the old version of your data model. When-- in order for Core Data to open up your original data model for the migration, it needs to have a copy of that source data model. So use the Xcode design menu to add a new model version when you're getting ready to make changes.

Don't just go changing your old data model. Second, you need to enable the migration objects. You need to infer mapping models at them at the option to infer mapping models automatically and the option to migrate persistent stores automatically. Now there's a detail I glossed over with renaming entities and properties. For-- the inferred mapping model to understand what your intention is when you're deleting an old attribute and adding a new one versus renaming an attribute.

We've added a new piece of API to specify the renaming identifier. And you can specify this directly in Xcode design-- model design tool and you can see here the field is shown in the-- this is the attribute configuration inspector and I've got the song entity selected here, the title property, and this is the version 2 of my data model.

So in order to rename and-- in order to rename the name property to title and be able to migrate that data from my source, data storage to the destination, I just need to put in the old name right and renaming identifier field. And inferred migration or lightweight migration will take care of inferring that change automatically.

So this already provides you a huge value in terms of workflow efficiency, it makes-- making model changes a lot less stressful, it's easier, you don't need to worry about adding an attribute or replacing the name of a value, but there's a huge other benefit to it. Because of the changes can be-- are unambiguous and relatively simple, the entire migration process can be done in the database without fetching any rows into memory.

It uses SQL to transform tables and update rows.

And it's really the fastest, least amount of memory way to do data migration. Now if you get unexpected results or you run into problems with using lightweight migration, there are a number of default that-- defaults you can set to enable logging during the migration process.

And these defaults work on the desktop only. To enable migration logs, you want to enable-- oh, I'm sorry I meant to say, I've displayed the syntax here for passing these defaults as arguments to your executable. So you can do that right in the Xcode executable inspector. But you can enable migration logging and SQL logging. And since the migration, if you're using a SQLite store it's being performed entirely with SQL statements. You can see a lot of what's going on by just enabling the SQL logs for that.

So to sum up with lightweight migration gives you, it's simple migration for simple changes, it's very easy to set up, and it's exceedingly fast. So especially on the phone, you get a huge benefit for using this when you can. And for those cases where you're-- making a data model change that's too complex or it can't be handled with lightweight migration. You can provide your own custom mapping model for those steps.

So now I'd like to turn my attention to Spotlight search integration. And you're maybe wondering, what's new about that? We have offered Spotlight search integration since our first release-- since Core Data was first released in Tiger. We've provided a document-based Spotlight importer and it works great for finding Core Data documents. But what about non-document-based applications where all the records live in a single file? Let's look at an example of what Spotlight does when you're dealing with documents versus non-documents-- non-document-based apps.

So if I search for barbeque, something I'm fond of, I'll get all of the documents, Spotlight correctly gives me all the documents that reference that term. But with a non-document like non-document-based app like dictionary, it is actually giving me the matching records inside. And this is something-- well let's take a look at another example. So if I do a Spotlight search for Malcolm, I want the results to match individual records, and they should open up an Address Book. But it's-- it's got it to go one step further.

It needs to display the matching contact. And this is what we've added in Snow Leopard with Core Data. It's a new Spotlight search integration template and it's a better user experience for non-document-based apps. And it gives you a way to integrate Spotlight search in way in your application that you can find and open individual records. And this is all documented in the Core Data Spotlight Integration Programming Guide.

It uses standard Spotlight APIs, you're still doing all the same kinds of things that you would do with a document base Spotlight importer. The importer creates the index but we have added a new Spotlight importer template for non-document-based applications. And here's another difference, this importer imports from external record files instead of your store file. Well, what are external record files? Well this is something new that we have added. And these are managed by Core Data.

Each file identifies a managed object uniquely. The property data still lives in the persistence store but by giving this-- but by presenting external record files, it gives the Spotlight a way to track individual records in your application. So you can create external record files in your application. To create external record files in your application, you need to specify a file extension for the external record files.

And you also need to mark properties to be indexed in Spotlight. And this is another new thing we've added to the Xcode design tool for your data model. There's a new checkbox you'll see, there is also API to support this. But the easiest way's right in the Xcode design tool, to use the checkbox, to index in Spotlight.

And the part that we take care for you, I said we managed the external record files. One, every time you save changes in your context, we synchronize the external record files on disc with the state of your Data Store. So when you update a record, we touch the external record file. And when you delete a record, we delete the external record file.

And this file system activity triggers the Spotlight importer and lets the Spotlight index stay up to date and in sync with the state of your data store. So there's a new project template called the Core Data Spotlight integration template that includes a template for non-document-based Core Data apps.

And in the new project assistant, you can see there's a new checkbox, I selected Cocoa application to use Core Data for storage, but now I can also specify, "I want to include the Spotlight importer." And you can see that the document-based application is not checked. So what do you need to do? You need to customize the template code.

It's just like the document-based Spotlight importer in that way. In your importer, you want to look up their properties that you marked in your model to index in Spotlight and then add that property data to the Spotlight index. And when you do that, you want to use the proper metadata tags for Spotlight to be able to provide the results in the best way possible. But here's the thing, since you have accessed to the entire store deck, external record file just tells you how to find the store file and the managed object that you're interested in, everything is accessible.

So you can pull in related data from other objects and you're not restricted to just working with the managed object you're indexing. The other thing you need to do is take care of displaying those search results. In a document based application, it is sort of automatic. When you open a document, your applications are already designed to display that. But in a non-document-based application, you're going to open external record files.

So you need to register your app to open external-- the file extension for those external record files as Core Data for the object ID from the file, and then fetch and display the record appropriately in your interface. So this is-- we're really excited to give you a way to achieve the same level of quality of integration with Spotlight in your non-document-based applications now. We take care of managing the tricky part of keeping the records in sync on disc and you do basically the same job you had in the past with the document-based application or you customize the importer and display the records that match.

Now I'd like to shift gears and talk about fetch performance. So what are the fundamental ideas of fetch performance? You want to fetch as little as you can, fetch only what you need. How much can you really put on screen? Think about your working set. On the iPhone, it is pretty obvious.

You only have got a few records on screen at a time. And even on the desktop, it's hard to imagine the user interface that can meaningfully show more than a few hundred records to the user at once. So the guiding philosophy here is to keep in mind what is the size of your working set and to try and keep things trimmed down to that as much as possible. And Core Data already provides a lot of options for dealing with a large data set.

Letting you fetch less data when you're working with it. You can fetch managed objects for records that you're actively working with. But for records, you just need a reference to. You can fetch object IDs or faults. And you can even just fetch the count when all you need to know is the number of records that match.

But what about when you're dealing with interface or UI that wants your entire data set provided as an array? Since the user is driving the access to that data, the access can be random and many records may not be displayed at all. So if you fetch an array of managed objects and you hand that over, you're using up way more memory than you want to. And if you hand over an array of faults, then every record that you access, that view accesses will trigger a fetch and a round trip to the database to fetch that data.

So, on the one hand, you're using up way more memory than you want to. On the other hand, you're incurring an awful lot of I/O and you'll see sluggish performance. To address this, we've added a new option to fetch request to fetch in batches And it provides random access to your data set so you're not fetching all of your records at once and it limits-- and it allows you to amortize the cost of the I/O because every fetch to the database fetches a batch of records.

Additionally, when you're-- when you're not actively holding on to records in that data set, the batch fetching array can release those records and free up those resources.

And all you need to do to use it is call "setFetchBatchSize" on your NSFetchRequest and it will return to you in auto-batching array of proxy when you do your fetch. Sometimes you need to display a large table of data but only show a few properties like in a master/detail view.

If your master view is only showing one or two properties but your records define a lot of properties that get displayed in the detail view-- well let's take a look at an example, sorry. So you've defined your song entity here and it defines all of the attributes that you need to keep track of.

And in your master table you're only really interested in showing two of them, the title and the rating. So to populate all of the values in that table, all you really need to do is access those two properties off of your songs. And now you've got a way to choose exactly the properties you want to fetch, call setPropertiesToFetch on NSFetchRequest.

And when you fetch your objects, the managed objects will be pre-populated with only those objects-- only those properties that you specified. But these are full managed objects and you get all of your business logic included. If you access properties that aren't pre-fetched, it'll cause a fetch to go to the database to populate the remaining values.

Also if you change any values on your managed object that'll cause a fetch to fill in those values too. So that is something to be aware of. If you are using partial fetches, you want to avoid accidentally tripping a lot of faults one after the other and burning I/O. We've also added the option in Snow Leopard to include or bypass pending changes. This is a new fetch request option and you can-- it's enabled by default, pending changes are enabled-- are included by default when you fetch. But you can bypass them by calling setIncludesPendingChanges no.

So why would we want to include pending changes? Why would you want them? Because it gives the user a consistent view of their unsaved data-- of the state of their unsaved data. Deleted objects will be omitted from the fetch-- from a fetch from the database and updates an inserted object, will be reconciled, will affect of search results when you do a search.

Well, why would you want to bypass pending changes? Well, sometimes you do not want them. Maybe you just want the state of your saved data. You just want to fetch against the state of your saved data. And there are other times where you got a query that really is tuned specifically to be executed in the database and you don't want to evaluate it in run time, in memory. Another case to be aware of is, if you have a lot of pending changes, in-memory evaluation of a predicate can be expensive.

So I've covered a few of the new fetch options and these are advance fetch options that we've added in Snow Leopard to NSFetchRequest. And we can, you know, a couple of ways to deal with UIs and APIs that want an entire-- your large data set all at once, and also giving you the option to bypass unsaved changes when you do not need them.

And now I would like to invite Melissa to talk about some advance fetch techniques.

[ Applause ]

Adam's talked a lot about the new features we have added to fetching that allow you to control the managed objects that come back. But sometimes a managed object isn't the answer to the question you're interested in asking. Sometimes you actually want different data back. Sometimes you want an aggregate value. Sometimes you want a collection of distinct values. These aren't managed objects.

What you really want is something that will let simple queries return simple values. For those of you who've tried to do this in previous versions of Core Data, you know that the way you get an aggregate is to load all of the objects that have a value that is part of the aggregate value you're interested in. Iterate it through each of those objects, retrieve the piece of data you want, do whatever calculations you need, and then use the results.

Similarly, if you want distinct values you would load all of the objects, iterate through them, pull out the piece of value-- the piece of data you want, drop it into a set, return the set, and release the managed object collection. Now we've given you a way to load only the specific data you want to do data aggregation in the database to just get distinct values back from the database.

And to get those results back as dictionaries instead of managed objects. What can you get back? Well, we were trying to flat [phonetic] dictionary. A key value pair allows you to specify what you want whatever you-- are getting back to be called and a value and its value.

An NS value, a number, a string, a date, an NS data, and get back object IDs, if you want. But you can't get back our collections, no too many relationships. How do you do it? It's actually pretty simple. We've added a new class, NSExpressionDescription. As you might guess, it's part of the model description classes and what this does is encapsulate description of the data you want back from the database.

You create an NSExpressionDescription, you give it a name, that is the key we will use in the dictionary we're returning. We give an expression-- an expression resultType which describes the data type that's coming back from the database, so we know what we're expecting to pull out of SQLite.

And you give it an expression describing the data you want back. We support most of the same NSExpression types that are supported in predicates passed to the store. And I should say at this point that this-- the read-only oata feature is primarily centered on the SQL store because all of our other stores do not really know how to do-- quickly do distinct or aggregate type calculations in the database. Once you go out NSExpressionDescription, what do you with it? Well that again is pretty simple, you pass it to NSFetchRequest. Adam talked earlier about the propertiesToFetch API that we've added to fetch request and that's reused here.

You take your NSExpressionDescriptions, collect them all up and pass them as an array to propertiesToFetch. We have added new resultType and NSdictionary resultType that says, you want whatever is coming back as dictionaries instead of managed objects. And optionally, we have added an API, returnsDistinctResults, which will tell-- which will specify whether what you want back is a collection of distinct results or not.

And because everything seems hard until you see it in code, except sometimes the code itself looks hard, we've added an example. Here you can see us doing aggregate fetch. We create up top an NSExpression and it is an expression that says, "I want the sum of the values in the key-- at the key path of duration." Using that expression we can create an ExpressionDescription. We set its name to total time.

We set it-- the expressions the one we created in the first step, and we set the expression resultType to NSDecimalAttributeType, 'cause well, we expect the duration to come back as some number of minutes plus some number of seconds. Then we take the ExpressionDescription we created, pass it to NSFetchRequest that created somewhere off screen. Set its propertiesToFetch to that array and set the resultType to NSDictionaryResultType. We then call ExecuteFetchRequest on a ManagedObjectContext and we get back something that looks likes this.

It's a dictionary with one value in it, a total time. Similarly-- oh, and to save you having to scribble that down or reverse engineer it yourself, we've actually associated a sample with this particular session, it is called "Read-Only Core Data." If you go look at it, it'll give you examples of how to use the various features of the read-only fetching. Another example that is also in there is distinct values.

This is how you create or fetch, returns distinct values. In this case, we want distinct values, a title and create an expression, keep out the expression for title. We create an ExpressionDescription, in this case, we're just going to use title as the name, set the expression, set the resultType to NSStringAttributeType because titles are strings. Create our array and set the propertiesToFetch, set the resultType and say, we want distinct results, distinct results yes.

And again, there's an example of how to do this in the read-only Core Data sample. We've also expanded the variety of predicates that supported in Core Data in Snow Leopard. That it supports for KVC operators, or at least the ones that makes sense in an SQL database. Min, max, sum, count, average those are all there now.

We have added support for functions, do you need to do math in the database for some reason? Do you need min, max, average, sum? Do you want upper case or lower case strings as you're doing comparisons? There is more function as well, see the NSExpression.h header for that. We've added a couple new string comparison flags in the parser.

We've added an "n" for normalized, what does this mean? Well, if you're familiar with doing string searching and string comparisons in the database, you'll know that well, string comparison is expensive. And the common technique that we've talked about in previous years, and it's common on the web, is that you want to normalize or pre-process all of your strings before you pass them into database.

Strip out diacritics, strip out any case, stuff, do whatever you want to get it into canonical form. If you use the "n" string flag when you're doing-- creating a predicate that specifies that whatever you've got is canonicalized and that we do not need to do any string processing on it.

We can treat it as a large bag of bytes and just compare the bytes. It is much faster to do this. We do not have to do any of the calculations and computations that come along with Unicode. We have also added a flag "l" for doing well locale-sensitive comparisons. And in addition, we've added support for the various string-comparison flags to the equality and inequality operators.

And this is stuff-- all the stuff we've done make a difference? Well, it's easy to say it, so we'll also going to show it. Like I said, we've got a pretty simple demo application, has a table view up top that has bunch of songs and their ratings. Under that, it's got some aggregate information about the songs, the song account min/max ratings, average. All the average really tells me is that my random number generator did a good job of generating random numbers.

And down here we've got a detail view that shows information about the song that's selected. So I'm going to have a look at that in instruments and see what there is to see. You know, once a very long time ago, we had to do stuff like this using FS usage and that was kind of a pain.

And then we added logging code and this-- the logging debug features Adam talked about earlier And now, we have instruments which really rocks and I highly suggest you use it because it is the best way to discover what your application is doing. So I'm going to create an instrument, a new document using the object alloc instrument. I'm going to add in Core Data fetches and Core Data cache misses instruments, because this is what we're interested in looking at.

I'm going to say that we should launch my demo executable, I'm going to run it, and for some reasons it's going to pop out behind the instrument. I'm going to scroll down and click on that-click on a row and click on a row and click on row. That should be all we really need to do.

And down here, I have another instrument that I got preset up that's the same application running with the same values. Only it has a command line parameter saying, "Use the Snow Leopard features." And the same-- I'm going to do the same thing here, I am going to scroll down, click on a row, scroll down, click on arrow, scroll down, click on a row and click.

Well, what can we see here? Let's go have a look. If we first look at the object alloc instrument, we can see down here that the number of live bytes, well, we got-- how about 5 meg of live memory. So what do we have over here? Oh, darn it.

I think I messed something up.

[ Pause ]

Well, that did not quite work. But we can see is we turn through a lot less overall memory. Demos, they're evil. You can see that we did the same number of fetches. Wait a second. That would be what's wrong. Instrument is helping me when I don't want help.

Let's try that again.

[ Pause ]

Ah-hah! That looks better. So, here we can see the application without the Snow Leopard features is using 8.5 megabytes worth of live memory. Well with partial faulting and using aggregates to get our values come back, we can see it's only using 5 meg. So that's a pretty significant and hefty chunk of memory that you're saving there.

And that's really important especially in a device, there's resource constrains of the iPhone. You can also see that the overall bytes we've used in the original application running without the Snow Leopard features is close to 40 meg. We've used 25 percent less. Again, that's kind of important. That means, less banging on mallet blocks [phonetic].

If we look at the fetch instrument, we can see that in the original application, I did four fetches, each one of which ended up bringing back a whole lot of objects from the database that I had to iterate through and pull values from. If we go look at the fetch instruments over here, well, I only have one of those mass [phonetic] fetches and that was to populate the table. The other ones only brought one back-- only brought one value back.

Conversely, if I look at the cache misses instrument, I can see that the types of objects that were brought back in the first, I was only having to go to the database to get albums, artists and genres. That's because those are relationships of the tracks that are being displayed in the table view.

And-- but if I go over here and look at what I was fetching here, I can see I'm also fetching albums and artist and genre. But I am also fetching tracks and that's because I was using partial faulting. And when ever I clicked on a row in the database, whenever a row became selected, I had to go to the database to get the information that was not being displayed in the table view, so the balance there between memory performance, CPU performance, I/O performance.

And that's a balance that everybody is going to have to decide what's best for their particular application. We can't give you an answer. We hope we can give you tools to help you more easily configure your application in the ways that are best for your application and for your dataset. And this is where I show for bugreporter.apple.com.

We gathered some miscellaneous APIs in Snow Leopard and this is all been stuff that people have asked for. You ask. We achieve. We've added a new method prepareForDeletion to NSManagedObject, this is called "front lead object" immediately before an object is going to be deleted. This allows you to nuke caches, do any clean up that you want to do before an object becomes deleted. We've also added awakeFromSnapshotEvents.

A Snapshot event is essentially an undo or redo and this notifies your object, it's a call back, it notifies your object that it's been-- it's participated in an undo or redo. And that if you've got caches that were calculated those caches and it may now be out of date, or you know, you may want to grab resources that you released as a result of something else that you now need again.

[ Applause ]

We have added a couple of new features to NSManageObjectContext.

Context should ignore un-modeled property changes. My, that's an awful long method name but it does pretty much exactly what it says it's going to do. It tells the context that if a property is not in the managed object model, don't mark the context as dirty as a result of any changes made to that property.

[Applause] See, like I said people asked for it. This allows you in a document-based application to set up caches and transient relationships or what have you at document open time without having the document mark itself as dirty. We've also added an existing object with ID API. You pass this to Managed Object ID and it will return an object to a fault if one exists in the Managed Object Context.

And it was-- return nothing if it hasn't yet been loaded. There may still be an object in the database. You just won't get a pointer to it back because you asked if there was one existing in the context. And that's pretty much it for what I'm going to talk to-- talk about for Core Data and Snow Leopard.

But other people have also been doing a lot of interesting stuff in Snow Leopard and we'd want to talk a little bit about how to integrate Core Data with some of the things other people would have done in 10.6. And first thing we're going to talk about is Grand Central Dispatch.

This is a really cool technology, makes threading a lot easier, 'cause threading is kind of a pain as anybody who's ever done it knows.

Techniques we're going to talk about also apply to Leopard if you're using NSOperation because NSOperation and NSOperationQueue first appeared in Leopard And actually, I believe we're the inspiration for libdispatch which showed up in Snow Leopard.

It allows you to pass tasks off to work queues that handle all the nasty details of threading behind your back It supports serial or concurrent queues and what you do is you submit a block, new objective C2.0 feature, blocks for execution. And at some future point, that block will be executed.

There is one and only one Core Data approved technique for doing this and that's thread confinement. In threaded code, that means that every thread gets its own Managed Object Context. In GCD, it means anything that might execute concurrently gets its own Managed Object Context. And if you need to communicate between threads of operation, you need to pass object IDs back and forth between the threads. Visually, it looks a lot like this.

You can see here, we have a couple of serial queues and all the tasks blocks that are on queue 1 are using Managed Object Context 1. But a block that is on queue 2, since it offer-- can be evaluated concurrently with any of the blocks that are on queue 1 has its own Managed Object Context, Manage Object Context 2. Going further, if we have a concurrent queue to this, you can see that all blocks on a concurrent queue need to have their own Managed Object Context because those could be evaluated concurrently with each other or concurrently with whatever is on one of the serial queues.

Everybody's life gets easier if anything that connects queue concurrently is in its own-- has its own context. And you don't need to lock, it means you do not get bizarre threading errors, just do this. And because it's tricky, and because everybody makes mistakes and that includes us, we have a set of assertions that can be enabled using com.apple.CoreData.ThreadingDebug 3. This will bring your application to an immediate and abrupt halt if any of the threading assumptions are violated. It will be usable in a debug version of the framework which should be downloadable from ADC shortly after Snow Leopard goes jammed.

And if you want to integrate with Instant Off, which is another new feature that's been added in Snow Leopard hasChanges on NSManagedObjectContext is now observable for the specific purposes of Instant Off. It is very important that you not change the object graph if you are observing it for the purpose of Instant Off, or if you're just cheating.

Because who knows what's going to happen if you try and notify your object graph while handing a notification that resulted from the object graph being notified. We make no guarantees. You may succeed. You may hurt yourself. If you need to change the object graph, you need to save or something like that, you can call performSelectorAfterDelay or one of its associated methods and sending a delay of zero.

This is a special number used to indicate that it needs to happen during the Instant Off context. So we're hoping you'll take away from this session is knowledge of the new features that we've added to Snow Leopard and sort of a sense of how you might use them in your application, what problems they're intended to solve.

Some best practices for using Core Data and for interacting with-- having Core Data interact with some of the other technologies in Snow Leopard. And some techniques like the Spotlight integration and the migration-- the lightweight migration that will help you accelerate your development cycle. Make it easier for you to get your apps out to your customers earlier. If you got any comments, compliments, questions you can ask Michael Jurewitz who is our Evangelist, whose email is up on the screen.

We have lots and lots of documentation for you. Starting point-- my favorite starting point is the framework overview page, that's a URL. I'm sure you can find it by googling for Core Data. Let's see. If you have an issue bugreport.apple.com, this is the only way you can know-- we can know what we think.

As I said, we added the new-- 11 of the new features as a result of customer demand and it came through this. So if there's something you want to see, there is something you think we are doing wrong, just a new feature that you think would make your life and everybody else's life easier, let us know. 1