Video hosted by Apple at devstreaming-cdn.apple.com

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

WWDC11 • Session 315

What's New in Core Data on Mac OS X

Developer Tools • OS X • 44:33

Learn about the latest advancements in Core Data on Mac OS X Lion, including improved fetch request API, ordered relationships, new incremental store support, and iCloud Storage APIs. Discover how you can adopt these powerful enhancements in your Mac OS X Lion apps.

Speakers: Ben Trumbull, Melissa Turner

Unlisted on Apple Developer site

Downloads from Apple

HD Video (200.3 MB)

Transcript

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

  • Okay, good morning everyone. Yes, thank you. And it is still wonderful to see you all here to talk about all the changes we've made in Mac OS X Lion. And it's good to be back in San Francisco. My name is Ben Trumbull. I'm the engineering manager for Core Data. And we have a lot to go through today. Talk about some of the highlights that we've added in the last year and a half or so.

And we're going to talk about some concurrency changes we've made to Core Data. Our integration with Lion's autosave feature. Ordered relationships. Some integration support with iCloud. A new incremental store API to do custom incremental stores with your own persistence mechanism. And then we're going to run through some highlights of developer tools changes in Xcode. So first up, concurrency. So the NSManageObjectContext is sort of the root part of the concurrency policy that Core Data has been providing. And we've added some new types of concurrency using NSManageObjectContext. There's some block-based methods, and we've also added nested context support to move changes around.

So to just take a quick step back, I'd like to talk about a little bit where we were. So earlier, in 10.4, 10.5, and 10.6, we really strongly encouraged you stick to a thread confinement model with NSManageObjects. And here we have a little diagram where we have a number of different queue types, and different blocks running on those queues are using either the same ManageObject context, if they're all on a serial queue, or between different serial queues, they're going to have to use a different ManageObject context. And if you wanted to use it with a concurrent queue, then you're going to have to have a separate context per block.

So thread confinement, separate contexts for each thread, manage objects are all owned by the thread that owns their managed object context. And really the only thing that was safe to pass around were the managed object IDs. So this served us pretty well. It's a very easy to understand model. Developers can make it happen without too much trouble. It's safe and it's very efficient for transactions. We don't get bogged down in excessively fine-grained locking or anything like that.

But in response to feedback from you and our own experience, it does have some issues, right? The coordination is left as an exercise to the client of the framework. The developer needs to track which context is associated with which thread, which thread created which context. And it does get a little cumbersome to pass extensive amounts of unsaved changes between threads.

So, we spent some time thinking about this, and thankfully a bunch of other Mac OS X technologies evolved, including LibDispatch, since we first came around. And so, we made this move to make a more formal concurrency policy, where in the Manage Object Context Initializer, you declare what kind of concurrency policy you would like to use with that particular context. And so, the new initializer is init with concurrency type, and there are three different types. There's a confinement concurrency type, a private queue, and a main queue.

So the NSConfinement concurrency type is really just the name of what you've been using in the past. This is what worked from 10.4 to 10.6. It's just thread confinement. Managed objects are owned by the thread or the queue that created them. And this is the default behavior if you called the old initializer.

So the private queue concurrency type is new in 10.7 and iOS 5. And here, it's basically an inversion of the thread confinement model. You can only call the Managed Object Context API on its own private queue, and the way you do that is by passing a block to the context with a new method called performBlock. And within this block, you just use the Managed Object Context.

and then there's a main queue concurrency type, which has got a very similar requirement, except the queue is always the main queue. And what this allows to happen is the UI and controller classes are all bound to the main thread, like all of Cocoa bindings, can work with the managed object context directly. They don't have to worry about new API issues.

But other threads in the background can easily pass results to these managed object contexts, just as if they were using the private queue concurrency type. They'd call perform block, and that ends up on the main queue. And this is very convenient for receiving results from background fetching and saving.

So the queue-based concurrency type, there's the main queue concurrency type, primarily for integration controllers in the UI, and the private queue concurrency type, which is a little more of an actor-style inversion of a thread confinement where the managed object context owns its own queue and it handles the scheduling for you. And then there are two API methods, performBlock and performBlockInWait.

So, Perform Block is asynchronous. Core Data considers it to be sort of the scope of a user event, a more substantial operation, and I'll define that in a couple of slides. And it includes an auto-release pool. It doesn't support API reentrancy, so if you call Perform Block from within a block, running on the managed average of context, it'll just get added to the end of the queue, very similar to the other queue APIs in Mac OS X. And it is important to note that please do not ever throw an exception outside of Perform Block.

Perform Block and Wait, as you might imagine, is synchronous. And it's intended to be a little lighter-weight operation, so we don't consider it to be a full event. There's no auto-release pool. And it does support API re-entrancy. So if you call Perform Block and Wait from within a block, running on the managed object context, it'll execute immediately. And also, please don't throw exceptions.

So this user event notion. So Core Data, particularly for Managed Object Context running on the main thread, has a lot of integration with the main event loop of that application in response to what the user's been doing. And this is the part where Core Data's providing change coalescing, delete propagation, integration with the NSUndoManager, and posting a lot of the NS notifications, like NSManageObjectContext objects did change at the end of every substantial operation.

So from Core Data's perspective, technically, this is in between the time that you make calls to process pending changes. And it just so happens that the main thread has a little run loop action to always call process pending changes for you. But when you call perform block, we're going to consider that discrete block to be basically an event in which you want at the end to get these notifications and to get change coalescing to occur.

Just to emphasize, when you use the private queue concurrency type, we really mean it. The queue is very private. So please don't grope for the queue. And if you want to then take results out of the blocks that you're executing from within perform block, you can just call into a dispatch sync or dispatch async or NS operation queue at the end of your block and just capture references to a queue that you actually own yourself.

Now, you might think that's a little inconvenient if you're trying to coordinate a large set of operations across multiple queues. But in fact, there's a nifty little operation that you can use called dispatch group. And what this lets you do is coordinate blocks across multiple different queues. And the nice thing about this API is you can actually tell it to coordinate external events that it doesn't even necessarily know about.

So you do that by using the dispatch group enter and dispatch group leave. And so with perform block, you can create a dispatch group and call dispatch group enter for every block that you want to track. And then at the end of your worker block in the managed object context, you call dispatch group leave. And then at the end of that, you've sort of set up the counting semaphore properly. And you can just use dispatch group wait and dispatch group notify to coordinate across many different queues and blocks.

So once we have all these different concurrency policies, we decided to add on some additional work, a nested NSManage object context. And this is to help pass changes between different contexts. So you just create a new context and set its parent, and the parent can have multiple children.

And you can do things with them like you can push changes to the parent and then have the child context continue on. So you can do an asynchronous save in that fashion where the in-memory changes just get pushed up and then the child continues on its way. And the parent context can save asynchronously. You can share unsaved changes between child contexts with the same parent. So you could do something like inheriting changes in a detail inspector. And you can also use it as a convenience to implement background fetching and some other tasks.

So the asynchronous save operation is pretty straightforward. You just save the child and then ask the parent context to save asynchronously. And this is what the UI Manage document in iOS 5 is actually doing right now to implement asynchronous saving. And the code looks kind of like this. The parent context has to adopt a queue type, and then the child context sets its parent. The child saves synchronously, and that will push its changes up in memory one level.

And then you ask the parent context to perform a block asynchronously to save the changes out to your store. And then sharing unsaved changes is pretty trivial. You basically push those changes up into the parent. They're in memory. They don't do I/O to save that out to the store. And you pull the changes down in another peer context.

And for inheriting changes, this just works naturally for all the child contexts you create. They always inherit the changes from their parents. So any saves are gonna push those changes up one level into the parent, and fetching will incorporate all the unsaved changes in that parent. And then you can do some things like, in your detail inspector, if you have a cancel model, you can just throw away the child context because its changes never actually got committed.

And some important things to remember. Saving is only going to push changes up one level if you create a very deeply nested tree. And fetching is going to pull all the data down from the database to make sure that the child sees the latest changes from everywhere. And then object with ID and the other faulting methods are going to pull in the fewest levels necessary, so they'll stop as soon as they find cached data. And parent contexts must always adopt one of the queue types. They can't use thread confinement since we kind of expect that they're going to be called from multiple different threads.

So that kind of wraps up the concurrency, and we'll talk a little more now about our autosave integration. There have been a lot of changes to the NSPERS system document. And so for Lion's autosave, just a quick overview of why we're doing this, users had to explicitly save and save regularly, and not necessarily save at very convenient times, titling their documents and such.

So these documents save automatically in place, and there's UI to lock versions and browse versions and a bunch of different support on NSDocument. And so what we've done in Core Data is improve NSPersistentDocument to play with these new APIs. So even untitled documents are going to get saved, and these save in place, so incremental operations against the SQLite store will behave kind of as you'd expect. So we're not creating a whole new document every time you save, just as we did in the past.

It is opt-in. So on your NS persistent document subclass, you'll need to implement autosaves in place. And this is the same as the NS document API. So to clarify the different types of autosaving, because in the past NSPersistent Document didn't support autosave on 10.6. NSPersistent Document still doesn't support the old-style autosave operation, and perhaps the easiest way to think about it is the current Lion autosaving is autosaving in place, and the old-style autosaving is creating sort of automatic backup files, sort of a little more along the lines of Emacs tilde files and stuff like that. And so NSPersistent Document will only autosave in place.

And if you decide to override the right methods declared on NSDocument, on your NSPerson document subclass, then we do encourage you to always call super. There's quite a bit of tricky handling to get autosaving to work with SQLite and all those different moving pieces with the versions browser.

So we do recommend you start considering document file wrappers. There are a couple of known issues with this, but by and large, going forward for iCloud syncing and external binary data, and just in general for yourselves, to put in caches for QuickLooks or Spotlight or anything else, the document file wrapper is really quite handy.

So there's sample code for using file wrappers with Core Data documents, and it overrides the read and write methods on its persistent document. There is a new Lion autosave example coming very soon now. Unfortunately, that wasn't quite finished yet, but we should expect to be publishing that in the next week or two. So the NS persistent documents now, if you override the method, will automatically save in place, and they support the versions browser that NS documents providing. So pretty simple to enable, and we are encouraging people to consider using file wrappers in the future. So next up, ordered relationships.

So before we get into talking too much about ordered relationships, we would like to highlight sort of two different patterns that we've seen developers use. There's a sorting pattern, and then there's an actual ordering pattern. So the sorting pattern, you have a bunch of data, and you typically show it to the user sorted by different attribute values. And there's not necessarily any intrinsic ordering in the data itself. So this here is the view is imposing sort of a user preference on the ordering, and you can change it pretty easily.

On the other hand, you can also have arbitrary ordering for lists, like a shopping list, a recipe, steps, or even a list in a build inspector in Xcode or something like that. And here the ordering is actually important. You can't just resort things and end up with something sensible.

And it's typically controlled by the user. So the user is changing the positions of things. So ordered relationships are really intended to solve the second problem for sort of user-imposed ordering. And it assigns positions in the too many relationships. It's providing back an NSOrderedSet, which is a new collection class in Foundation.

So the NSOrderedSet behaves a lot like an array. It is, however, not a subclass of an array, and this is important because it does not allow duplicates. So NSArrays can have duplicated elements, and NSOrderedSets, while they have positions, each item is only going to be in the set once. And we'd like to call out that the order relationships are more expensive for maintaining both the positioning and the unicking.

So here in Xcode, it's pretty simple to enable them in the Xcode 4 inspector. Once you have selected a relationship property and you go into the detail inspector with a little cylinder cut out, you just select arrange. So that's pretty easy. So working with the ordered relationships, you can generate accessors for them in Xcode 4.

And there's also the immutable ordered set value for key method you can do to get back a mutable proxy that's KBO compliant to make mutations to your ordered relationships. and in a moment, currently, the dynamically generated KVC accessors on this managed object are not quite available yet for ordered relationships.

So for observing changes, we'd just like to call out that NSOrderedSet is a little bit different from both NSArray and NSSet. So what you're going to see is you're going to get back the same KVO observing method call, but you're going to get back different change kinds than you would from either an NSSet or an NSArray. So there'll be insertions and removals as opposed to unions and minuses.

And while you don't necessarily have to worry too much about this, we would like to highlight sort of one of the reasons why if you have sorted data as opposed to arbitrarily user-ordered data, that you'd probably be better off using an unordered set where it makes sense. And that's because we actually have to do quite a bit of work to do merging between changes in different contexts for these ordered relationships. So we do our best to preserve the relative ordering, but that can be pretty difficult to divine the user's intention. So the merging of positions is particularly expensive.

Migration, so you can migrate back using lightweight migration between ordered and unordered. Lightweight migration will just assign an ordering initially, that's arbitrary. So if you do want to upgrade to using ordered relationships, you can just impose a post-processing step after you've added the store with a lightweight migration phase to assign an ordering based on some other criteria.

So in summary, these are new ordered relationships, and we encourage them from arbitrary ordering, particularly if you are going to be managing an ordering column yourself anyway. So that's a great place to use them. And they're using a new NSOrderedSet collection from Foundation. And just keep in mind that the position merging is going to be a little more expensive than the regular unordered too many relationships. So you should use sorted unordered relationships where it makes sense in the UI. And now I'd like to bring up Melissa Turner to talk about our iCloud integration and the rest of the session.

[Transcript missing]

You'll get per-conflict record, per-record conflict resolution, the same as you would using two parallel managed object contexts and stacks in a single process. We only sync deltas over the network, so you don't have to worry about the bandwidth imposition your application is putting on your customers. We do asynchronous imports, so your application is going to continue to be responsive while your user, while data is being imported in the background.

And we provide a three-way merge that tries to preserve the intent of changes that were made on different devices, so that your final object The final truth of the object living in the cloud is what your user will expect rather than what they most recently changed. What does that really mean? Well, say I have a record.

For the sake of easy slide reading, it's a contact named John Doe with an address [email protected]. And I go off on vacation and I talk to somebody who knows John and he says, "Well, did you know he's decided to change his name? He's now Johnny." You go in and change that on your device.

You talk to somebody else later and they say, oh yeah, he didn't just change his first name, he changed his last name. He's now Johnny Appleseed. And at the same time, back at home, my partner is off, and they're talking to somebody about the same person. And they get told, oh yeah, did you hear he changed his email address? It's now johnny at strange symbol dot com. What you might expect is that when you're trying to merge all of these things together through the cloud, you're actually going to end up with either John Doe, johnny at strange symbol dot com, or Johnny Appleseed, john at strange symbol dot com.

But that's not what we do. We actually look at each of the chain sets in chronological order, and we apply just the diffs to the previous object so that we'll actually combine those, and in the end you'll end up with Johnny Appleseed, johnny at strange symbol dot com.

What do you have to do to get all this? Not a lot. You have to add some options to the options dictionary when you're adding your persistent store to the persistent store coordinator. And you need to respond to an import notification when we pull data out of the cloud.

What do we do? Well, we do a lot, actually. If you've heard the class names NSFileCoordinator, NSFilePresenter, or NSMetadataQuery, we take care of all of the integration with those for you. We also take care of exporting changes when they're made in your application and importing changes that have been made in other devices that are part of your cloud. And at this point, I'm going to try and do a demo and hope the demo gods smile on me.

So I have here an application. It's a little users and groups thing. And I'm going to come over here and create a user. Call it Beach Ball, because I'm not creative on stage. And I'm going to give it a picture. I'm going to add it to the water group.

And then I'm going to save. And I'm going to come over to my other computer here. I'm going to launch the application. And we can see that that new user was created. And at this point, you're probably going, yeah, you faked that. And a week ago, you might have been right.

But instead, I'm actually going to come over here and I'm going to add a new group. I'm going to call it Gingerbread now. I'm going to call it green. I think I'm going to give it the color green. I'm going to move flippers into the green group. And I'm going to save. Then I'm going to come back to my first computer. And we can see that Flippers, I now have a green group, and that Flippers is actually in that green group. It all worked. The demo gods liked me.

There's something about building applications and doing demos on stage that just guarantees that everything will go wrong. But what just happened there? So I had one computer and I created some data on it and I saved my application and that data was exported and pushed into the cloud.

My other application came up and asked the cloud, is there any new data that I need to know about? And there was, so it was pulled down and integrated into the store on that local system. And then I made some more changes. and saved, and those were pushed back into the cloud. And the other computer was notified that, hey, there's new changes for that application, and pulled them down.

And we did all this with three pieces of API, as far as you're concerned. Two store options, NSPersistentStoreUbiquitousContentNameKey and NSPersistentStoreUbiquitousContentURLKey, and one notification telling the application that it's time to update the user interface. And as persistent store ubiquitous content name key is kind of the identifier for your store.

Many of you know that a Core Data application can often have multiple stores for many reasons. I mean, often there'll be a set of data that was shipped with the application in one store, and then all of the user data was created in a separate store. And there's no really good way of identifying these stores. I mean, the name can be, well, a file can be a file name. Many different applications can use the same file name. Paths differ between Mac OS and iOS.

So we need a way to allow you to specify that the data in this store is from my application, and it should be in all instances of my application everywhere. And that's the persistent store ubiquitous content name key. can set any value you'd like as long as it's file system compatible, no slashes or colons. And that's all you need to do to say this store is this store everywhere.

You can also set an NS Persistent Store ubiquitous content URL key. This is optional. By default, if you've got a single store in your application and you have the same bundle identifier on all platforms that you want to sync data between, you can just use the default. If you've got a different bundle identifier between Mac and iOS, then you'll need to provide your own identifier that we can use to say, OK, this iPhone app and this Mac app are really talking to the same data off in the cloud.

And this is where you'll find it. You'll also need to set a ubiquitous content URL key if you're doing document syncing. This should be treated as an opaque package. We put stuff in there. Don't poke at it. You're likely to break something. And we reserve the right to change it at any future point.

How do we get, how do you get a persistent store ubiquitous content URL key? Like I said, it defaults to the main bundle identifier. And if you ask NS file manager for the URL for ubiquity container ID for your bundle identifier, it will provide you for URL. And if you want to provide a custom persistent store ubiquitous content URL key, you'll simply append stuff onto the end of that URL according to the rules that are set out by the document syncing APIs, the document in the cloud APIs.

The NS Persistent Store did import Ubiquitous Content Changes notification. This is very much like the NS Persistent Store did save notification. It has an object, which is the persistent store coordinator that has the store mounted. If you have multiple persistent store coordinators in your application, which have the same store mounted, you'll get a notification for each persistent store coordinator. User info for that persistent store coordinator has a dictionary containing the collections of inserted, updated, and deleted objects that you need to know about. Unlike the NS Persistent Store did save notification, these are collections of managed object IDs instead of collections of managed objects.

How do you respond to an import? Well, in pretty much the same way as you do, and as Managed Object Context did save notification. You'll refresh your unchanged objects so that the next time the user tries to access them, they'll pull the new data from the store. And you'll merge in changes for all of the objects that have been changed in the local context.

Well, this is really great for shoebox applications, but what about NS-Persistent Document-based applications? Well, it's going to be easiest if you sync documents as file wrappers rather than as single files. There's lots of reasons for that that I won't get into here. You'll use the ubiquitous store options when you add the store for the persistent document.

And one thing you should consider is you don't want to sync the SQLite file. You'll provide us with a ubiquitous URL path pointing to a location inside the document file wrapper, and we'll pull all of the stuff that needs to go into the cloud there. But the SQLite file itself doesn't need to go in the cloud, because we'll simply apply the diffs that have been made on other devices to the existing store. So you can tell us that you don't want the store in the cloud by including .nosync somewhere in the SQLite store file path.

If you don't want to use NS-Persistent Document but you still want to use Core Data, well, there's a couple of alternatives. Atomic stores can actually be synced as whole files. SQLite shouldn't be, but the atomic stores, well, they have always been last-writer wins. And that would be no different in the iCloud case. In this case, you'll want to use the NS-FileVersion APIs for resolving conflicts between changes made on different devices.

Some good ideas? Well, remember to respond to the import notification. This is the only way you're going to get your UI updates. Remember to use an appropriate merge policy in your context to make sure that data that your user is editing locally is merged in correctly with data that was changed in the cloud. Anticipate bandwidth constraints. Try not to thrash too hard. Don't save every time somebody changes a character and a string. Wait until they're done. And use no sync for all of the files that you're saving that you don't actually want to push into the cloud.

And now I'm on to NS Incremental Store. So, why do you care? I suspect some of you don't, but a lot of you, since we first shipped, Core Data in Mac OS X Tiger, 10.4 Tiger, have been saying, "Well, all of the store types you're providing are great, but I want to talk to something else." And that set of something else has grown over time.

And it's really hard for us to decide which ones are worth expending resources on, and what's better for us to spend time doing iCloud integration, because that's something that's a lot harder to do. So we're giving you an incremental store API that lets you talk to your data source in whatever language you would like to talk, in its own language. It's very much like the SQL store. It allows you to only load the data that you actually need. It supports faulting, so you can only load the data you need when you need it. And it supports flushing unused data once your user's done with it.

How does it work? For those of you who are interested in implementing a incremental store, you want to remember this slide, because it covers everything you're going to need to know about implementing a store, what methods are called, in what order they're called. So in the beginning, your application launches and a persistent store coordinator is created. And you tell it to add a persistent store of type your incremental store type. The store goes off, the coordinator goes off and creates an instance of that store and tells it, load your metadata.

And the store hands the metadata back to the persistent store coordinator, which looks at it and determines whether or not the contents of that store are compatible with the model that was used to initialize the persistent store coordinator. This is just like adding any other store. And if that's okay, the model, the entity version hashes in both places match, the coordinator mounts the store.

At some point, somebody adds a context, and now you have a full usable Core Data stack. And now your user is going to want to look at data. So your application will create an NSFetchRequest. And at that point, an executeFetchRequest is called on the managed object context. and that gets sent down to your store as execute request with context error. This is your store's cue to go off and figure out which objects the user is actually requesting. And you'll create shells for those objects and return them to the context.

As I said, these are likely to come back as faults, or they can come back as faults if you choose, and at some point, value for key is going to be called on one of those faults. At this point, Core Data will send your store a new message, new values for object with ID with context error. And this is essentially saying, "Okay, store, user's interested in this object.

Go off and get me the property values for it." If what you're trying to fire is a relationship fault, we'll actually send new values for relationship for object with ID with context error. It says, "The user's trying to follow this relationship. Get me the object or objects that are at the other end." So your user goes off and edits things, inserts a few objects, deletes a few objects, changes some stuff, and then they want to save.

And at this point, Your application will call save on the managed object context, and the managed object context will create a save request and pass that down to the store in two stages. First, we'll go through and look at all the inserted objects, and we'll tell your store to obtain permanent IDs for the objects that have been created. At this point, your store needs to figure out what permanent keys are going to be assigned to those objects and send them back to Core Data so we can actually connect all the relationships appropriately.

We then tell your store to execute requests with context error, and in this case, it's a save request. And the save request contains collections of objects that were inserted, updated, and deleted, and you'll need to take those objects and push them to your store in whatever language your store likes to talk, or your data source likes to talk. There is one other piece, and that's the NSIncrementalStore node.

Your store may talk JSON, it may talk SQL, it may talk something else. And Core Data can't understand all of those things, so you'll need to put the data in a format that Core Data can actually understand. And this is done by creating an instance of NSIncrementalStoreNode. You initialize it with the object ID for the object that this data represents, and with a dictionary containing key to property value mappings. And at this point, it's a black box. You can ask it for its object ID and for the value for the property description, but your data is now in a format that Core Data can understand. And that's all there is to it.

Sounds so easy, doesn't it? I talked about method execute request with context error, which leads me into talking about NSPersistentStoreRequest. This is a new base class we've added that basically uses the command pattern for Core Data to talk to your store. We've added a new class, NSSaveChangesRequest. This contains all of the information about objects that have changes in the context that need to be pushed to your store. We reparented NSFetchRequest, so it's now a subclass of NSPersistentStoreRequest.

Your execute request method will need to switch on these. And if it's a fetch request, well, you'll need to figure out what data your user wants. There's two types of flags on NSFetchRequest. There's flags that affect the content of the array that's being returned. Flags that determine whether what you're returning is an NSManagedObject, whether it's NSManagedObjectID, or whether it's a dictionary. Or whether it's just the number of objects that are being returned for account request. There's flags that affect performance. This is stuff like whether you should return faults or fully populated managed objects, whether relationship prefetching should be done.

If you're providing a store that you expect other people to use, you're providing a store to clients, You must implement all of the flags that affect the results of. and I are going to talk about the new features of the new Mac OS X Lion. So, let's get started. So, let's talk about the new features of the new Mac OS X Lion. So, let's talk about the new features of the new Mac OS X Lion.

We provide an API that allows you to map between primary keys and object IDs. It's the same API that we shipped with NS Atomic Store. And when you're returning values for fetch request, you should get the object, the managed objects, by asking the context that was passed to the second parameter with context for an object with a given ID. That will return a fault.

There is no SQL generator included in this. We're targeting this more at web services, but you can use it to build anything you'd like. And feel free to send us pointers, because we're really interested in seeing what you do with this. We suggest, and this is just because we've gone through it, that you consider supporting only a set of canned queries.

Pick a defined set of predicates that can be used to access the data you think your user is going to be interested in and support those rather than trying to build something that can and I are here to share a few tips on how to use the latest version of the NAS.

We will Some general design tips. In much the same way we suggest you use canned queries, we suggest that you design your store to talk to a specific schema. When you sit down and start doing a design, it's really easy to say, "Well, I want to build a store that will talk to my data source, but all possible versions of my data source." Therein lies madness.

Design your store to talk to the specific current version of your schema and worry about the future when it gets there. Make it a decent design that's reasonably flexible, but it's going to be a lot easier to concentrate on deciphering the data you have rather than any possible future set of data.

Try and remember to balance I/O and memory. You're going to have real problems if you're on an I/OS device, and every time you fire a fault, you hit the network. That's really expensive. People are going to be upset because there's going to be a lot of delay. Consider pulling data in in batches and caching it locally. And as I said, this is sort of really designed for talking to web services, although you can use it for everything. Even if you're talking to an Oracle database, it's usually best to go through a web service first.

And now I'm on to the developer tools. You've probably seen at this point that we've got a new version of Xcode. It's got a lot of nifty features, particularly in the Core Data world. There's a new UI. We have support for optimized models, readable diffable models, and scalar accessors. For those of you who are familiar with the diagram view, it's still there, but we've also added a new table view.

And this allows you to edit your model, your entities in a slightly different way. On the top left, you can see, in the center you'll see the table that contains all of the properties that are on a given entity. The top left, you'll see the list of entities, fetch requests, and configurations that appear in your model.

On the bottom left, you'll see the button that allows you to add entities, fetch requests, and configurations. On the bottom right, you can switch between editor styles between the table view and the diagram view. This is where you add attributes, relationships, and fetch properties. And on the top left, we've got the detail inspector. This is pretty much the same thing you had in the top right on, Xcode 3.

Optimized models, what are they? Well, they're a way that Core Data encodes your model format that's smaller and faster loading than the previous version. You'll get this automatically if you're using versioned models in Xcode 4. It lives in parallel with the versioned models. You don't need to do anything to pick it up. We've also added human-readable Xcode 4 models. I won't say user-readable because no user should have to read these.

This is also automatic in Xcode 4 and will be a transparent upgrade from the old format if you decide that you want to use Xcode 4 models. They're XML based and they're perfectly compatible with your favorite diff tool. How do you get them? You go in and set in the Core Data model inspector in its file inspector the minimum supported version to Xcode 4.1.

We've added support for scalar accessors in Core Data, and this is accessed, again, through Xcode. When you're creating your accessors, there's a checkbox on the wizard that walks you through it that lets you specify that you want your accessor methods to return scalars instead of NSValue classes. We've added support for Arc. This makes memory management easier by avoiding the need to implement or call retain or release. It's opt-in per project, and new project templates enable it by default. It's opt-out per file, and if you're interested, we highly recommend you go see the session or watch it on iTunes.

We've added external binary data. For many years, we've gotten up on stage and told you that you really should consider storing things like movies or large pictures outside the database. We keep saying this, and we finally decided to make it easy for you to do. So if you've got a binary attribute that you know is going to be storing large pieces of data, you can go into the property inspector for that attribute, and you can select allows external storage.

And what this will do is tell Core Data that this is a really big thing, maybe you should consider putting it outside the store. For stores that support it, and the SQLite store does, we will look at your data blob, and if it's over a certain size, we'll store it out beside the store instead of storing it inside the SQL store. And this really helps search performance, because it helps localize the references when you're doing a table scan.

Vetted support for compound indices. This is an index across multiple columns in a SQLite database. Why do you care? This helps, again, speed up searching. How do you add them? Well, On the Entity Inspector, we have a new field that allows you to enter comma-separated lists of property names. We'll turn those into compound indices.

So we've added a whole bunch of new features that we hope will make your life developing with Core Data a lot easier. We've added concurrency. New block-based concurrency models, block-based, queue-based concurrency models, and nested managed object context to help you push and pull data that you only want to edit locally. We've added support for autosave.

We've added ordered relationships. I know you've been asking for those since Tiger. I've been dealing with bugs since Tiger. We've added support for iCloud, and we really hope that you can use this to make your application data appear everywhere. This is something that is so exciting. It's really cool. We've added support for incremental stores. Talk to your data store in whatever language you'd like.

and use Core Data to manage it. And we took you on a quick trip through what's been added to the developer tools in Xcode 4. And this is where I show you the same slide I show you every year that says if you find a problem with Core Data, if you find a bug or there's something you wish it would do or there's a performance issue or whatever, we can't read your minds, please file bugs, let us know. We'll fix bugs faster if there's steps to reproduce in a sample project, but sometimes just knowing that there's a problem out there is good enough.

For more information, you can always email Mike Jurowicz with feedback. He listens. There's a lot of documentation out there if you're trying to learn Core Data, and there's more all the time. And we do lurk on the Apple Developer Forums, so that's another good way of providing feedback.

This is a list of related sessions. Unfortunately, they're all in the past, so you'll have to catch them when they show up on iTunes. This is the iCloud Storage overview, the autosave inversions overview, taking advantage of file coordination to understand just how much Core Data saves you work when you're using our iCloud integration, and the introduction to Arc. And we're done. Thank you very much for coming.