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: wwdc2012-224
$eventId
ID of event: wwdc2012
$eventContentId
ID of session without event part: 224
$eventShortId
Shortened ID of event: wwdc12
$year
Year of session: 2012
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2012] [Session 224] Using iClou...

WWDC12 • Session 224

Using iCloud with NSDocument

Essentials • OS X • 45:45

NSDocument provides a powerful way to adopt iCloud Storage on OS X. Learn how NSDocument can help your document-based app more easily adopt iCloud. Dive into Auto Save, learn to work with versions, and understand the app-centric open panel and user workflows.

Speaker: Kevin Perry

Unlisted on Apple Developer site

Downloads from Apple

HD Video (300.4 MB)

Transcript

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

Good afternoon. My name is Kevin Perry, and I'm an engineer on the Cocoa Frameworks team. Today, we're talking about using iCloud with NSDocument. Your users get their work done inside of your application. And we want to eliminate as many distractions that take them out of your application as possible.

There are some cloud implementations expose themselves as a folder or volume that requires the users to often drop down into Finder to manage their files, organize them, and do things like resolve conflicts. With iCloud, we're able to remove these distractions by integrating the iCloud experience directly into the application.

This provides a seamless user experience. The user is able to resolve conflicts right in the app. They're able to manage their documents without having to go into Finder and so forth. This integration does put additional responsibility on applications. However, for document-based applications on Mountain Lion, NSDocument takes care of all the UI and functionality that is required from document-based applications when using iCloud.

These features include file coordination, which is required to properly communicate changes to and from iCloud. Document Management UI, Conflict Notification and Resolution UI, and alerts for exceptional situations. For example, when a user's document isn't being uploaded to iCloud because they're over quota with their document storage space. So let's dive in and talk about the first step to enabling these iCloud document features, and that's adopting iCloud in general in your application.

To do this, you need to properly set up your application's provisioning profile. Provisioning profile is a document that identifies your development team, defines the devices your application can run on, And grants iCloud support to your applications. And finally, defines your Ubiquiti container, which is the location on the local computer where the instance of your user's documents are saved with iCloud. The provisioning profile is configured and downloaded from the provisioning portal, which is on the developer website. There's lots of documentation there about how to set that up there on the website, so I'll just refer you to that.

The next step is to add proper entitlements to your application. And this is really as simple as just a few clicks in Xcode in the new version. So let me go ahead and switch to a demo where I can show you this. Here we have the venerable Sketch sample application. And first thing I want to show you is here in the organizer.

You can see in the provisioning profiles, I've already got my provisioning profile that I've configured for Sketch imported here. So that's really the first step. The next is to go to the project summary. And down here you see An option to enable entitlements. So let's click that. We don't need sandboxing for this particular demo, but we do want to now add an iCloud container for this application.

Kick Plus. NX code automatically populates this with the container name that I specified in the provisioning profile. The last step is to switch over to build settings here and make sure that we're signing the application with the proper identity. See here I have the one that matches the provisioning profile for Sketch. Select that. Build and run.

And here we have Sketch, and the first thing you see is the new open panel, which you saw during the keynote. This is built directly into the application and provides a very simple and familiar user interface for managing iCloud documents. It's a matter of double-clicking to open a document. And to add or remove documents to iCloud, the user can simply drag a document in.

or drag it back out similarly. And they can even delete documents directly from iCloud. So any of the file management that a user would need to do with iCloud documents is handled right here in the open panel. You don't need to implement that yourself in your application. Also, I have a document here that, when I open it, presents me with a conflict resolution panel. And I can get additional information about these documents, a preview, so I can make an informed decision about which one I want to keep.

Finally, you'll notice that when I create a new document and start to edit it, The document is automatically saved into iCloud. And this makes it really easy for users to get their documents into iCloud and share them between other applications. It provides a really streamlined user experience. So that's a very quick demo of all of NSDoctument's iCloud features. As I said, the first step to doing that is enabling, configuring your provisioning profile and enabling those entitlements.

There is one other thing that I, one other modification I made to the sample application beforehand, and I want to talk about this before we talk about more iCloud topics, and that's Auto Save. Auto Save is a feature that we added in Lion, and we really encourage all NSDoctument-based applications to adopt this feature. There are a lot of reasons why you'd want to do this.

First and foremost, it provides a modern document workflow so that users aren't required to think about the difference of what's on screen and what's on disk at any given time. To the user, we give them an illusion that they're the same, and effectively they are. Enabling Auto Save also gives you versions, which allows you to go back in time and revert to a previous version of the document.

Adopting Auto Save also provides a more seamless experience with auto termination and resume, since we're not required to ask the user about unsaved changes. As I mentioned, in order to get all of NSDoctument's iCloud features, you need to use Auto Save. One of the primary reasons is that enabling Auto Save turns on an implementation of file coordination that's built into NSDocument. Enabling Auto Save is very simple.

In your document subclass, override autosaves in place and return yes. But what implications does this have for your application? In short, it causes NSDoctument to use two new saving operations, NSAutosaveElsewhere operation and NSAutosaveInPlace operation. Before I talk about these new saving operations that we added in Lion, let me talk about the other saving operations that already exist in NSDoctument and have since the beginning of OS X.

The first is a save in place, which we show to the user in the UI as save, and the API for that is NSSaveOperation. The way this works is a document references a file, and as changes are made to the document and save with NSSaveOperation, we safely replace the contents of that referenced file with the new ones.

Save elsewhere, which we expose to the user as export, and in the API is called NSSaveToOperation. This works by prompting the user for a location, and then this document saves the current contents of the document to that new location, and then promptly forgets about it, and continues to save changes that are made to the document to the original file.

Save elsewhere and redirect is exposed to the user as SaveAs, and in the API, NSSaveAs operation. This works very similar to Save Elsewhere, in that we prompt the user for a location and save the current contents of the document there. However, from that point, the document now starts to reference this newly created file and forgets about the old one. Users often use this as a sort of ad hoc versioning mechanism.

When enabling auto saving in place, we add a new column to this table. All the prior three operations are all user-initiated, but these new ones happen automatically. They happen automatically for several reasons. For example, when the user edits a document, and this document will start a timer and aims to save the document when the user is idle.

Also, when the user switches away from an application, that's a good hint that it's a good time to save, and indeed, the user might be trying to use that document to, for example, attach the file to an email. Also, file coordination can sometimes prompt your NSDoctument to save itself so that whatever operation reader or writer is trying to access your document has the latest contents.

Let's start with NSAutoSaveElsewhere operation. This is similar to export in that it uses a completely different file than the one the document references. NSDocument uses this for untitled documents that are kept locally on the computer. Since untitled documents don't have a user-visible file associated with them, but we still want to ensure crash protection and resume functionality, NSDocument uses NSAutoSaveElsewhere operation to save any changes that are made to the file in a hidden location in the user's library directory. This file remains until the user finally chooses to save as. A user-visible file is created, and the autosaved document is deleted.

And it's Auto Save in Place operation acts very much like an SAVE operation in that when the user makes changes, we save the contents directly over the existing file in a safe manner. The only difference is that this happens automatically without any direct user interaction. Let me show you another quick demo.

First, let's go back to the code and my document subclass, SKT document. And you can see here that I have indeed overridden auto saves in place, and I'm returning yes. And while Sketch is a simple application, it conforms very well to NSDoctumets API. And any application, even a more complex one, that behaves properly like Sketch, will have an easy time of enabling Auto Save.

So let's go back to the application. And you can see as I'm making changes to the document, up here in the title bar, you see that there's an indication that the document has been edited. This is a notification to the user that the document has been changed in case they have made unintended edits.

And right here, convenient in the title bar, is an option to revert to the last unsaved version, in this case, the last open version. And we convert to that very easily. Also, if I make changes and close the window, I'm not prompted about those changes because, again, what we see on the screen is effectively what's on disk at any given time.

Finally, we also have the option to browse versions. We're taken into this time machine-like interface where we can browse previous versions and choose one to restore. So that's a very quick overview of the features that enabling Auto Save buys your users. And again, we feel that this is the future of NSDoctument, and new features like iCloud and those that might come in the future will very likely be reliant on auto saving to function completely. When enabling auto save, obviously we're going to be saving without the user's knowledge and more frequently than the user might. Because of this, we need to ensure that the application remains responsive while auto saving.

The best approach to remaining responsive during autosaving is to make sure that you are saving efficiently, that your serialization of your in-memory contents is efficient, that you're not saving unnecessary data into your file, and so forth. However, there are some things that are out of your control when it comes to autosaving responsiveness, such as file system latency. In Lion, we had a couple of approaches to help improve responsiveness.

The first is asynchronous saving. The way this works is that when saving begins, you take a snapshot of your document's state, and then on a background thread, NSDocument will have you serialize that and write that out to disk. And this frees the main thread so the user can continue interacting with your application and even the very same document.

If asynchronous saving isn't feasible for your application for whatever reason, there's also cancelable auto saves. The way this works is that during a save operation, you can peek at the event loop to see if the user is trying to interact with your application. And if so, cancel the auto save if appropriate, returning control to the run loop and allowing the user to continue interacting with the application. And then NSDocument will respond by scheduling the auto save for some time in the near future when hopefully the user is idle.

For more information about these techniques, you can see the talk that we gave last year on Auto Save and versions. That's available at developer.apple.com. Another thing you need to consider when enabling Auto Save and iCloud is serialization. There are a couple of resources in NSDoctument that need to be serialized properly when you have asynchronous things happening like autosaving and events from iCloud. The first is User Activities, and the next is File Access. Let's talk about User Activities first. These include operations like Save, Revert, Duplicate, Print, and new in Mountain Lion, Move, Rename, and iCloud Conflict Resolution.

All of these activities are started either directly or indirectly by the user and have a few things in common. Most of them show some sort of UI that allows the user to instruct you how the operation is to be performed. Sometimes, the performing that operation results in errors that need to be presented to the user, and those errors can provide paths for recovery. All of these steps are wrapped up in an activity. Let's use printing as an example. Suppose the user is in the middle of printing a document.

And all of a sudden, we receive a conflict from iCloud. NSDocument is going to try to show the conflict resolution panel, which involves showing a sheet on the window. However, if the user is in the middle of printing, they're not really going to be able to understand properly what it means to resolve the conflict. And indeed, if we were to attempt to do this simultaneously, it plain wouldn't work because both printing and conflict resolution use sheets, modal UI on the window that requires exclusive access to that window. You can't have two sheets visible on the same window at the same time.

The solution to this is an API that we added in line on NSDoctument called PerformActivityWithSynchronousWaiting using Block. We wrap this entire activity from beginning to end in the block that we passed to this API. And what NSDoctument will do once we've done this is it will cause the subsequent activities to be deferred until all previous activities have been completed. And we signal completion by invoking the completion handle that's passed to this block.

Now, if your application doesn't provide any custom activities, you don't really need to think about this API. However, for those of you who do, I want to stress one point to make sure that in every path in your blocks inside perform activity that you invoke the completion handler because the results are not pleasant.

If you're not invoking the completion handler and this document doesn't realize that the activity is completed, and all future activities get pushed off into the future and never happen until that completion handler is invoked. This can result in problems like deadlock, which we want to avoid. Let me show you a quick demo of a situation that we ran into when an application was adopting iCloud, where perform activity with synchronous waiting was required to solve a problem. We'll use Sketch again to replicate this same scenario. I'll go to my Window Controller subclass.

And here in an override of show window, I'm going to enable some code that shows an alert that basically just tells you how many documents are in the window. And here in the window, I'm going to enable some code that shows how many graphics are in the document.

Not a particularly useful bit of information, but you can imagine an application that shows an alert when, for example, there's fonts missing that are required by that document. So let's go ahead and build and run with these changes and open up this document that I showed you before has conflicts on it.

You see here, the alert comes up as expected. However, when I dismiss this alert, nothing happens. I'm not shown the conflict resolution panel. And if I try to interact with that document further, the application hangs. So something is definitely wrong here. What's happening is that the alert, the sheet for this alert that I'm trying to show, is competing with the conflict resolution panel that NSDoctument is trying to show.

So as I showed you before, We can serialize these so they happen one at a time and don't compete by using performActivityWithSynchronousWaiting. In this case, I'm passing no because this isn't an action that's initiated directly by the user. And I'll move all of this

[Transcript missing]

And what I'm doing here is I'm invoking this method, which I have up here, that basically just invokes the block that's passed in as the context info pointer. And here I'm passing in the activity completion handler.

[Transcript missing]

So let's go ahead and build and run now. And open this document. We get the alert that I am showing. And once that's dismissed, the conflict resolution panel properly appears, and we can resolve the conflict. These two activities have been properly serialized, so they're no longer competing. The next kind of serialized resource is file access. And what I mean by file access is anything inside of your document that needs to be synchronized with the state of the document's file.

This includes the URL, modification date, the in-memory representation of the on-disk contents, and the edit state of the document, among other things. So reading or writing any of this information should be done protected by the file access serialization APIs that NSDoctument provides, or else you could be working with an incomplete or an inconsistent state of your document.

There are two types of file access APIs. There's a synchronous API that blocks the main thread until all previous, or the thread that it's invoked on, until all previous file access attempts have completed. It's invoked synchronously, and when the block that you pass to it returns, the file access for that block is relinquished automatically.

There's also an asynchronous API, which works by enqueuing the block and returning immediately. And that block will be invoked sometime in the near future when all previous file access attempts have completed. This asynchronous API is required to work safely with documents on non-main threads. And when doing so, when you need to resume work on the main thread prior to relinquishing file access, you need to be sure to do that using continuous synchronous work on main thread using block, which is another API in NSDocument that we added in Lion. And it helps avoid deadlocks that can happen in this particular scenario. And there's a lot more information about this API in last year's Auto Save Inversions talk as well.

Sometimes bugs happen. You forget to call the completion handler for an activity or an asynchronous file access, and the result is things like hangs and blocks never executing. Sometimes these hangs happen, and you look at the backtrace, and you don't see any of your own code. Instead of assuming that it's a bug with the framework, You should consider problems that might be within your own application. However, these were very hard to find in line because there wasn't any information in the backtrace or so forth.

In Mountain Lion, we've made this debugging experience easier by leaving breadcrumbs, stack traces, wherever activity and file access APIs are used so that you can go back and trace this information. You can access this with a debug function called underbar NSDocumentSerializationInfo. And this name could change at any time. It's not in any headers. So again, please don't use this in code. But you're welcome to use it in the debugger.

I'll show you a quick example of a case where, how you might use this. I've got an application that's hanging, so I look at the back trace and I see code that doesn't belong to me, it belongs in NSDoctuMent. But near the top of the stack is perform synchronous file access using the block.

So I assume that there's a previous file access attempt that's not finishing up and blocking this particular one. So I PO underbar NSDocument serialization info, and this dumps a bunch of information that helps me track down the problem. First I find the stack trace that matches the current hang, and I see that it is indeed waiting for previous file access to complete.

By looking up earlier in this dump, we see an active file access that was initiated by a method called DoSomethingWithFile. While it could be possible that this is just taking a long time to complete, I suspect that there might actually be a bug here. So let's look at the code. Hopefully this looks familiar to my earlier demo. We see an attempt to perform asynchronous file access. And inside here, when the file URL is not nil, we perform some file access. And in this completion handler, we invoke the completion handler for the Perform Asynchronous File Access API.

Those of you with a sharp eye will notice that when the file URL is not nil, I was failing to call the completion handler, which resulted in all future file access attempts to block infinitely. So this debug functionality that we've added in Mountain Lion makes pinpointing this problem a lot easier.

The last topic on Auto Save is versions. Versions is how we implement revert functionality in Auto Saving applications, and also the versions browser. It works by NSDoctument periodically preserving document contents when it deems appropriate. does this in a very disk-space efficient manner, only saving the changes that were made from previous versions.

And it's important to note that this happens automatically. Most applications don't need to bother with anything about versions. It happens without you doing anything, just by enabling Auto Save. However, there were some optimizations that we made to version preservation in Mountain Lion that some applications may need to be aware of. There are two times when NSDoctument might decide to save a version. One happens immediately prior to saving.

In Lion, when we decide to preserve a document during saving, We would copy the document into the version storage in a manner that happens synchronously on the main thread. Then finally, wrote the new contents of the document. This could result in a long wait for the user when the document is sufficiently large that the copy takes a while. In Mountain Lion, we added an optimization that takes advantage of the backup file that happens during NSDoctument safe saving. And NSDocument Safe Saving can work by first moving the document, renaming it so that it has a different name, indicating that it's a backup.

Once that file is moved aside, then we write the new contents in place. And since the backup file contains the prior contents that we wanted to save into versions, we can simply move that file into the version storage since the user doesn't need it anymore since the save completed successfully. This avoids the wait for the copy that we had in Lion.

Again, most applications don't need to think about this. It happens automatically. But those who override the method WriteSafelyToURL of type for save operation error and don't call super need to be aware of a contract that now exists between this method and its caller. That contract is that before the method returns, writeSafetyURL is required to save the original contents of the document to the URL specified by backup file URL when that method returns a non-nil value.

Kevin Perry Some applications that override writeSafetyURL do so to implement incremental saving in place. In these cases, it might not be possible to efficiently save the previous contents of the document to backup file URL in an efficient manner. Kevin Perry In this case, it's appropriate to override backup file URL and return nil. This is a signal to NSDoctument that this optimization should not be used and the old version preservation. technique be used instead.

And NSDoctomate also preserves versions after saving, when the user explicitly saves, since we use that as a hint, meaning the user is interested in this particular version and may want to go back to it in the future. and Mountain Lion, we did this preservation by, when we finished writing, copying the newly saved version of the document into version storage. This happened on the main thread in a manner that, again, when sufficiently large, would block the user from interacting with the application.

In Mountain Lion, we simply moved this copy onto a non-main thread. And this happens for any applications linked against the 10.8 SDK. This eliminates the hang on the main thread. And most applications don't need to think about this, since most file access happens through NSDoctument's saving path. However, if you do any additional file access, you need to make sure that that file access does not happen during the copy.

If you attempt to write to that file example, for example, while NSDoctument is trying to save it into versions, you could end up with a corrupt version of the document in the version storage. So the solution is to wait until the end of that file access by using the file access serialization APIs that I showed you earlier.

So that's it for Auto Save. There's several topics that we discussed today, but primarily I want you to get across that, again, we believe Auto Save is the modern document experience that we want to provide for users. So they don't have to think about the difference between what they see on screen and what's on disk at any time.

And it's also the last step to enabling iCloud in your NSDoctum based applications. So let's return to talking about it and talk about the mechanics of how iCloud works, starting with the UI. I showed you a quick demo earlier about how to open iCloud documents. This is done primarily through the app-centric open panel. This open panel is unique because, unlike previous versions of Mac OS X, it is non-modal.

And as such, we need new API on NSDocumentController to support this.

[Transcript missing]

So we've added beginOpenPanel with completion handler, which is a method you might invoke, for example, in an override of NSDoctrl's open document, and beginOpenPanel for types completion handler, which is a method you might override to customize the open panel.

Getting documents in and out of iCloud is also done primarily through the app-centric open panel. But NSDoctoment also provides menu items called Move To and Move to iCloud, which allow the user to move documents anywhere on the system without having to leave the application or very quickly directly to iCloud. These operations are implemented with a new method on NSDoctoment, Move to URL Completion Handler, which you can override if you need to do any customization of a move.

The last way documents get into iCloud is drafts. Drafts are a new concept in Mountain Lion. And the way it works is that whenever the user creates a document in an iCloud-based, an iCloud and its document-based application, that document is destined to be saved into your application's Ubiquiti container. Indeed, when the user starts making changes to that new document, NSDocument will save a user-visible file directly into the Ubiquiti container using an a Save As operation, which I'll discuss in a moment.

When it does so, it marks this document as a draft. And what that means is that the user hasn't chosen an explicit name or location for this document. So when the user chooses to explicitly save or close the document, we'll still show the Save panel to allow them to choose an explicit name or location or delete the document if they decide they don't want to keep it after all.

Kevin Perry This draft status remains until the user chooses to save, rename, move, or any other operation that tells us that the user is interested in keeping this file around indefinitely. And that happens, the draft status is removed, and we no longer show the Save panel on Save or Close.

There are several APIs related to drafts available in Mountain Lion. The first is, as I said, NSAutoSaveAs operation. This fills in the last space in the table that I showed you earlier. It's an automatic operation that happens when the user edits the document. And it's very similar to Save As in that it creates a new user-visible file,

[Transcript missing]

There are other APIs, such as accessors, for the draft status of a document. You have the ability to customize the name of a draft.

For example, if your application uses templates for creating untitled documents, you can give the user some more information about what these draft documents are by, for example, using those template names. In a word processing application, you could have a template for a resume or a newsletter. And when the user creates these drafts of these templates, they can be saved as these names in iCloud instead of untitled, untitled 2, untitled 3, so forth.

Finally, if there is a special case where you have a document subclass where drafts are not appropriate, you can disable them by overriding Auto Save's drafts and returning no. Let's move on to how iCloud works under the covers a little bit more in depth. Maybe we can talk later about how your application should interact with iCloud.

When your application wants to make changes to the document's file, it starts a coordinated write and saves the document within that coordinated write. When this coordinated write happens within the Ubiquiti container, the system notices this, takes those changes, and uploads them to iCloud. And those changes are made available to all other devices connected to the same iCloud account.

In the other direction, when receiving changes from another machine, those get uploaded to iCloud. and download it to your local machine. What the system will do is it will itself start a coordinated write. And if that particular document is still open in your application, it will take note of that. And when the write completes, it will revert to show the user the current contents of that document.

Finally, sometimes changes can happen simultaneously or simultaneously in the point of view of iCloud. And when those changes get uploaded to iCloud, it doesn't have enough information to make a decision about which file is supposed to be the most current. So instead of attempting that, it uploads every version of that document to every peer, and it's the user's responsibility to decide which version to keep going forward. And once the user makes that decision on one machine, that decision is propagated to all of the devices connected to the same account. Now let's talk about best practices when enabling iCloud in your NSDoctument-based application.

First, override NSDoctument as little as possible. NSDoctument provides a lot of functionality for you, and the less that you override, or the lower level that you override NSDoctument's methods, the more that you're going to get for free, and the more consistent you're going to be with other applications on the system.

Next, the open panel for iCloud provides a simplified view of the user's iCloud document library. And as such, it does not show the accessory view that may be attached to an open panel. So your application should look at alternative ways to providing the same functionality as your open panel accessory views to get the same functionality.

Since NSDoctument's conflict resolution panel uses Quick Look thumbnail and previews, Your application should provide a quality Quick Look generator so the user has as much information as possible when resolving conflicts. This is good advice in general, since Quick Look is used throughout the system. Next, you should think about file formats. First, think about forward and backward compatibility.

Sometimes users will not have the latest version of your application on all their iCloud-enabled devices. And so you need to be prepared to handle what happens when the user attempts to open a document created with a new version of your application with an old version, and vice versa. Also, if your application has both Mac OS and iOS versions, You need to make sure that there isn't any device-specific information saved in the file that would not be interpreted properly on a different platform.

So, on iOS devices, as you know, the file system isn't accessible by the user. And it's possible to hide information in files on iOS, such as an undo stack. This isn't really appropriate when using iCloud because those files get synced, get downloaded to OS X devices. So, on iOS devices, as you know, the file system isn't accessible by the user. And it's possible to hide information in files on iOS. And it's possible to hide information in files on iOS.

For example, when your device receives changes from iCloud, how does it respond? It is probably not a good idea to respond by writing to the file. This would result in that change being uploaded to iCloud, downloaded to another machine, which would then react by making another change to the document, which gets uploaded to iCloud, and so forth. You end up with a ping-pong situation, which not only wastes network traffic, but is generally problematic.

It's also possible for users, of course, to view their documents on multiple devices. And these devices may not be connected to the internet at every moment. So you want to make sure that all the changes that get saved into your document are the result of direct user edits to that document. If you save other information like scroll position or current selection, this could result in a situation where unintended conflicts are created, which could be confusing to the user since they haven't actually made any significant changes to the document.

Finally, be sure you test reverting. This is used extensively with file coordination in iCloud. When changes are downloaded from iCloud, again, NSDocument will revert to the current contents of the file. This is so the user can see the latest state of the document as downloaded from iCloud. And you need to make sure that your application shows those new contents properly. Kevin Perry The same goes for conflict resolution.

When a conflict is presented and the user chooses a different version to keep, NSDocument reverts to that version to reflect that decision. So NSDoctument provides a lot of functionality for you, as you can see. And it's built on several foundation APIs. The first is file coordination. Again, NSDoctument registers itself as a file presenter and does file coordination when reading and writing the document. There's also a URL for Ubiquity Container Identifier on NSFileManager. This is the API used to give you the location of the iCloud container for opening and saving documents there.

NSMetaDataQuery provides API for finding and getting updates about iCloud files. And there are some new APIs in Foundation in Mountain Lion. The first is Ubiquity Identity Token. This is an API that gives you an opaque token representing the currently logged in iCloud account. What's interesting about this method is that when the user has disabled iCloud documents or has logged out of iCloud completely, this method returns nil.

And since this method is very quick at returning, it's appropriate for invoking on the main thread when you need to check if iCloud is even enabled in your application.

[Transcript missing]

There's also a notification that gets sent out by NSNotificationCenter when this identity changes, when the user enables or disables iCloud documents, or when the user logs in or out of iCloud. This is NSUbiquity Identity to Change notification. You can also use this API together with the Ubiquity Identity token to detect changes between changes any user's iCloud account so you can react to that properly.

Finally, it is possible to disable all of NSDoctument's iCloud features, with the exception of file coordination, since that's not specifically iCloud. It's used for proper file coordination with the rest of the system. But all of the UI and so forth that NSDoctument provides, you can disable by overriding users' ubiquitous storage and returning no.

So we talked about a lot of topics today, about Auto Save, how to adopt it, how to ensure responsiveness in your application when auto saving, how to ensure proper serialization, and things you may need to know about with versions. With iCloud, we showed you how to adopt that in your application, how it works in the UI and underneath the covers, and best practices. There are a lot of sessions related to iCloud at the conference. Earlier today was using iCloud with UIDocument. This, of course, is the OS X companion to that talk. There's also a Using iCloud with Core Data talk after this on Thursday at 4.30.

And an Advanced iCloud Document Storage talk tomorrow at 3.15. This is appropriate if NSDoctument doesn't really apply to your particular application, or you need to do a little bit more with iCloud. For more information, this is a contact info for Mike Jurowicz, the Developer Tools and Performance Evangelist. That's it. Thank you for coming.