App Frameworks • iOS, OS X • 46:30
The next version of the Foundation framework will include file coordination, a new mechanism that allows a process to interoperate well with other processes that are accessing the same files. It even lets your application play an active role in file operations done by other processes. We'll talk about what it is and how you use it. It's an important API to some of the other new features you'll learn about at this year's WWDC so we'll also talk about how parts of Mac OS X and iOS are already using it.
Speaker: Mark Piccirelli
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it may have transcription errors.
Good afternoon. Welcome to session 109. I am Mark Petrelli. I'm an engineer in the Cocoa Frameworks group. Today we're gonna talk about file coordination, a new technology, and I'm gonna talk about what it is, and why it's important, and how to use it. First, I'll actually talk about why it's important, and one of the big reasons is iCloud. It's one of the fundamental technologies underlying it.
So in iCloud storage, the piece of iCloud where the user's own documents go back and forth, in running on the user's system, there is our iCloud system, a collection of agents and daemons that take care of, you know, moving files around and on the network and off and things like that. And then there'll be applications like yours. Actually, that's TextEdit. It's ours, but it's sample code, so think of it as yours. So--and then the files that are in the cloud.
And what needs doing for a file that's in the cloud is when updates come in off the network and when they're pushed, iCloud will write the changes to the file on disk, and then your application has to read them. And likewise, when the user changes a file, the file has to be saved on disk so that the iCloud system can pick the changes up and send them over the network. So a lot of this was covered earlier today in the iCloud storage overview.
But what we end up with in this situation are some problems we have to solve caused by the fact that there are multiple processes accessing the same file. So, for example, one process writing while another is actually reading is potentially a very bad thing, as the thing that's reading reads something that's half-baked because the writing is still going on. So we have to answer the question, how does a process know when it's safe both to read and to write?
Another thing we have to answer is the problem that iCloud will change files and then your app must read them. So we have to answer the question, how does a process know when it must read? And the last thing is that iCloud needs your files up to date to do conflict detection. So that as the user is editing them, there are times where iCloud has to command your application to save the contents to disk so it can look at it. And so that raises the question, how does a process know when it must write? The other feature that file coordination is for is for autosave.
And autosave is a new document model for Mac OS X where the user never has to save, and the window on the screen is the file as far as the user is concerned. So--and this is all just covered in the rather excellent presentation that preceded this one, "Autosave Inversions in Mac OS X Lion."
And so for an example of when this is an issue, if you have a document that's open in TextEdit and the user's editing away at it, and they do something like picking it up in Finder and dragging it into Mail to make an attachment out of it, Mail wants to read the contents of the document, but it doesn't want to read out-of-date contents. So how does it tell TextEdit to save the changes to the file so that it can read something that's up-to-date and make a Mail attachment out of it?
And so, you know, autosave introduces this problem for us, the possibility of processes reading out-of-date files, and that would be bad. So once again, the question has to be answered, how does the process know when it must write? And the answer to these questions is file coordination. So file coordination, first of all, is a locking mechanism. It's how applications serialize access to the same files by preventing one process from reading while another writes. It's also a notification mechanism. If you're using file coordination, the writing that your process is doing might cause some other process to read, and your reading might cause some other process to write, and vice versa. The API takes, is in two pieces, the NS file coordinator class, and it's the class you use to do coordinated file access. So this is a new bit of terminology for you.
Of course, for many decades, people have been reading or writing files, and there have been locking mechanisms, of course. But now we're introducing the notion of coordinated file access, where it works with other things that are doing coordinated file access. The other half of it is NS file presenter, which is a protocol that you implement to hear about coordinated file access. And this is, of course, available on both Mac OS 10.7 and iOS 5. It's actually in the foundation library. - Thank you very much.
So a quick snippet of what it looks like basically. NSFile coordinator, the two main methods are coordinate reading at item at URL and coordinate writing item at URL. And the basic notion is that tell us what you're doing and we'll tell you when to do it. And the way you tell us what to do is by passing a block.
And you pass in a block and when it's safe for your process to read or write, as in no other process is reading or writing right then, will invoke your block. And while your block is being invoked, other processes are held off from beginning new reads or writes. NSFilePresenter, just to touch on it so you know for the rest of the talk, is the notion, "Tell us who you are and we'll tell you what to do." So it has methods like presentedItemDidChange and presentedItemDidMoveToURL and savePresentedItemChanges and accommodatePresentedItemDeletion.
And the first two of these are things you would think of as a notification mechanism. You register an NSFilePresenter when your application is presenting a file to the user, and you get to hear about other processes-coordinated file access when they're done. What's a little more novel are the second two methods, savePresentedItemChanges and accommodatePresentedItemDeletions. You actually get to affect other processes-coordinated file access. Another process is going to read. You get to control what it does read by saving first.
So when to use File Coordinator, when to do coordinated reads or writes. You should use it with files that the user thinks of as files, and mostly this is applicable to Mac OS X, right? Because that's where the user sees files. And when you do this, you're coordinating with other things like the finder and other applications, other things that are also accessing those files. And you also want to use it for iCloud documents, even though the user doesn't think of them as files in a file system. They are. So you want to coordinate with the iCloud daemons and system components that are also reading and writing those files.
And your goal is to play well with other processes. And an important thing to do with that is that you can't possibly enumerate what all the other processes are going to be, and you don't know what they're going to do. So I'm going to be showing you, you want to use, you know, coordinated file access. There's a specific way to do that where you're not even really supposed to care what's happening in other processes. And of course, as time goes on, there's going to be more and more things using NSFile Coordinator, so you'll be interoperating with things aren't even there yet.
So you wanna use File Coordinator when you're reading. And again, this is a, you wanna use File Coordinator when you're reading files. When you're creating files, including for example, exporting, you have a document. The user has a document open in a window and they export it. You wanna coordinate the access, the writing of that, so that if for example, something that is watching the file system starts reading just because something appeared there, its reading doesn't start until your writing is done.
updating, as in, you know, auto-saving documents, and copying files-- Finder does this-- and also moving and renaming files. Again, Finder does this. And this applies to directories, too. The class's name is NSFileCoordinator, but you want to coordinate some operations on directories also. And so a lot of this stuff, by the way, NSDocument and UIDocument already do this for you. So NSDocument, for example, when it's opening or saving documents, does coordinated reading or writing.
So when not to use File Coordinator, like any interesting mechanism, it can be overused. So I can let you off the hook right away. Some places where you don't want to call it. Temporary files that your process has made just for itself and also cache files, even if they're going to stick around for a long time. And anything private enough to your process that you know that there's no reason for any other process to be digging around in it. So there's no reason to coordinate with nothing.
When to be a file presenter, whenever your application is presenting a file to the user for viewing or editing, it's gonna be in a window that stays up on the screen for a while, and the user might be able to do something with another application that'll be changing it while that window is up. So, and all this, by the way, also applies to file packages too, which are on both Mac OS X and iOS, directories that appear to the user as single files.
And you do this so that you can reload the document when other processes change it. And also, perhaps close the document when other processes will delete it. So when the finder is about to empty the trash and there's a document still open in it, it should be closed. Otherwise, it will just be a window that's not connected to anything, and great confusion results.
Another thing I'm going to mention is that there is an even-- there's another mechanism in NSFilePresenter that allows you to relinquish files to other processes. When you register in NSFilePresenter, we don't like the terminology to say that the file presenter owns the file, but it does have sort of a right of first refusal over other things being able to read or write to it without its permission first.
And this is another thing that both NSDocument and UIDocument do this for you. When you open an NSDocument or UIDocument, it registers itself as an NSFilePresenter. And when it's closed, it deregisters itself. - Yes. So NSFileCoordinator, the first big half of this API. First of all, it is a locking mechanism. If you catch me afterwards, I can go into why we're not using other locking mechanisms that are already there, like BSD advisory locks or something like that. Actually, the release notes go-- enumerate what's wrong with those. But they're still locking, and we implement pretty standard locking rules. Readers don't block readers. Readers do block writers.
Writers block readers and writers block other writers. File packages are interesting because they're treated atomically. If you do a coordinated read of files in a file package and something else wants to do a coordinated write of a file in that file package, the writer will be blocked until the reading is done because we want file packages to always have consistent contents.
And this is already a little bit of a power user note for you. NS file coordinators don't block themselves. So you can instantiate an NS file coordinator and use it to do a couple of different things at once, knowing that you won't create a deadlock just within your own code.
The way you create an NSFileCoordinator is with the initializer, in it with FilePresenter, and we want to encourage you to instantiate one of these per operation. And by operation, I mean something kind of big and lumpy, not like opening the file is one operation, then reading the file is another operation, then closing it is another operation. Just opening it and reading and closing it, all the stuff that NSDocument does during document opening, that's one operation, deserves one NSFileCoordinator. And the same thing for saving, it's one operation, even though-- because of safe saving, a whole lot of things actually might be happening during the saving of a document. And we even want you to use NSFileCoordinator if you're doing pretty big batch operations. Like when Finder is copying a giant hierarchy of folders, which might take quite a while to do, that's still just one NSFileCoordinator that it's using for all of that.
When you create an NSFile coordinator, you get to specify an NSFile presenter, And what you're indicating when you do that is that the NS file coordinator is being created on behalf of that file presenter or is going to do something for that file presenter. So, for example, whenever NS document does a coordinated read or write, it always passes itself as this. And the reason you do this is it lets us filter out messages about your own file access. So sticking with the example of NSDocument, it implements a presented item did change, but it's not interested about changes it did itself. And without this mechanism, it would be pretty hard for it to filter those out actually. It also helps us break deadlocks, getting this linkage of file coordinators and file presenters accurate. You know, when something does a coordinated read and that causes a message for a file presenter of that read file and the file presenter responds by doing a coordinated write to update that file, that would be a deadlock if we didn't know that the file presenter's writing is because of the reading. So keeping these things hooked up prevents deadlocks.
So back to those basic methods, reading item at URL and writing item at URL. They both follow the same pattern. You pass in a block, and file coordinator invokes the block for you. And what's interesting about these blocks, by the way, is you get passed a new URL. So you passed in one URL that you wanted to read or write. Well, while your reader or writer is being made to wait, the file might be moved or renamed. And so you need up-to-date information about where the file ended up before you start reading or writing it. So we pass you a new URL. And as a little bit of esoterica, in Snow Leopard, we added NSURL caching of all sorts of properties. And it's always been a confusing question about, when do those caches get invalidated? Happily, when you're using this, the answer is, we'll pass you a URL when something else read or wrote while you're waiting. And it'll be a new one, even if it points to the same file. So it'll have an empty cache without stale values in it.
An interesting thing to note about these methods is they're synchronous. So if you are going to do something that you don't want to block the UI, you should do these on a background thread or in a background queue. And the reason they're synchronous, by the way, is because we wanna keep this very safe.
We wanna make it very difficult for applications to make each other look bad. So when your block is invoked, as soon as your block returns, other things will be allowed to do their coordinated reads or writes. Or if your process crashes, of course, other things become unblocked, or even if you throw an exception from within the block that you passed these methods. Thank you.
And it's a pretty simple example of how to read these or how to invoke these. Here is a fictional method called readFromURL in a fictional class, and it's doing a coordinated read by, first of all, instantiating NSFileCoordinator, and then it invokes the method coordinateReadingItemAtURL, and then this might wait a while, depending on what other processes are doing, but eventually it will always call your block, And you can do things like, in this simple example, reading the contents of a file into an NSData.
And what's interesting about this API, by the way, you know, blocks are still kind of new, and we're still designing new APIs with them. In this one, we discovered it was most convenient to actually require the use of a block variable, so block NSData, data equals nil. And inside, you know, the reading block, just assigning that value and then afterwards returning the data auto-released.
And then if something goes wrong, coordinate reading item at URL might return an out error, or I'm sorry, might return an error by reference. And when it does that, by the way, it actually doesn't even invoke your block at all. It just sets NSError. And in combination with this use of the block variable, it ends up being both correct and simple. But you have to, when you're working with blocks, you'll see that experience counts a little bit. So you'll see this ends up being pretty simple after a while. So what might have just happened while the block was not invoked? Well, your process might have been waiting for other processes that were writing to the file. And by that I mean other uses of file coordinator.
And the file might have even been moved or deleted during that time. So if you have reading code that does error checking, it still has to do error checking for things like the file just isn't there anymore. NSFilePresenter messaging, when it was reading the file, it might have told an NSFilePresenter to actually update the contents. and errors. The NSFilePresenter might have tried to save the file, but failed horribly, so that's why NSFileCoordinator can return errors.
So each of those two methods was for just reading or writing one file at a time. We also have a couple other methods that combine these operations. So coordinate reading item at URL and writing item at URL all at once. And an example of when you want to use this is when you're copying a file because you will be reading one file and writing one file at the same time. And the reason we have these kind of combinatorial operations in there is because it helps us avoid deadlocks. If you tried to do a coordinated read and then a coordinated write nested inside of it, that can cause a deadlock if some other process does a coordinated write of the same file and then a coordinated read of the other file in the other order. So we have a couple of these methods that just let you say what you mean more accurately to avoid trouble.
And another one in this vein is actually coordinate writing item at URL and writing item at another URL at the same time, which is what you use for moving. So because in this model, when you move a file, you're actually writing the two files. You are writing to the file that you're moving, picking it up and moving, and you're actually, if there is a file in the way at the destination, you'll be writing to that too by replacing it. Thank you.
So there's a handful of options in this API. When you're reading a file, you can specify that the file coordination mechanism itself should resolve the symbolic link if there is one there. And the reason we provide this, resolving symbolic links is not too hard, but when you're talking about how it interacts with a locking mechanism and you might actually be following a chain of symbolic links, that's kind of difficult to get right. So we do it for you, if you so choose. And it only applies to the item itself, by the way. Only if the file at the end of the path is a symbolic link does this matter, because we're resolving all the other symbolic links all the time anyway.
Another option is file coordinator reading without changes. By default, readers give NS file presenters of the file that they're reading a chance to write. But sometimes you're not interested. I've been describing this behavior where, you know, one file, one process goes to read and it causes another one to write. Sometimes that's not useful. So here's an option to turn it off. And iCloud uses it. And the reason iCloud uses it is because it's always watching the relevant files using FS events anyway. And it is doing coordinated reads and writes, of course, but if it does a coordinated read and it's not the latest thing that the user just, you know, edited on the screen, that's okay because when that's autosaved again, iCloud will see that with FS events and just, you know, grab that and push it again.
So there are writing options, too, on NSFileCoordinator, and no options means you are updating the file. And by updating, I mean something like, you know, like a save in NSDocument. So even when it's more complicated than something like, than just simply opening the file and writing it and then closing it, that's just one operation as far as FileCoordinator is concerned, and the example is safe saving of NSDocument. All sorts of things go on, but that's just one coordinated right.
And it's worth mentioning that we deal in what the user thinks of as files, not necessarily what really are files in the file system. So even during a safe saving, there's actually a couple of files involved. There's the one that's being overwritten, and then there's the one that's saved off to the side and then moved into place from the point of file coordinator. That's just one file, just as user thinks of it as one file. not always actual files. There are other file coordinator options that let you say what you mean, and the first one is writing for replacing, and you use this when you're creating a brand-new item or you're moving an existing item.
And we call it writing for replacing, even when you don't necessarily know that you are replacing a file, because checking for a file to replace doesn't really work in a file system, 'cause there's so many race conditions possible. You might check, and then by the time it really matters, you know, a file has appeared there, even though there wasn't one before.
So you just use this when the situation warrants it, very, very simply, instead of writing conditional code to figure out whether or not to use this option. And one of the things is it causes NSFilePresenter messaging where if there is a file presenter registered for the file that's being replaced, it will be told that this file is going to be deleted and replaced with another one at the exact same location so it can close a document or something like that. And we use it during NSDocuments save as and save to operations, which save a copy of the document that the user's looking at off into a brand new file.
So writing for deleting is pretty interesting because it has special handling of directories. If you say that you're doing a coordinated write to a directory, I'm sorry, if you're doing a coordinated write to a directory where you're using this deleting option, What that means is if something is already reading or writing a file in that directory, perhaps very deep in the hierarchy, we have to wait until it's done. We don't want to yank the directory and everything it contains out from underneath that.
And likewise, if a directory is in the middle of being deleted and something else tries to do a coordinated read or write into that thing that's being deleted, we make that second thing wait so that, you know, the directory will be deleted by the time it gets there, but that's something, that's the sort of error checking you're supposed to do anyway. So at least everything will be in a consistent state by then. Thank you.
And again, just like for writing for replacing, this tells NSFile presenters ahead of time that something is going to be deleted, including if you're deleting a directory, if there are documents open inside that directory, they will be told that they will be deleted with the rest of the directory. Thank you.
And writing for replacing actually does some of the same things. The distinction between writing for deleting and writing for replacing is actually too much to go into up here. You should check out the release notes, but it has to do with if something gets moved while something is waiting to access it. Thank you. And there is also writing for moving. It has the same sort of waiting rules as far as directories go. If a directory is being moved, it will wait until things are done reading or writing that directory.
So what's good about all this, by the way, is that operations on giant directories containing great big numbers of subfolders and files can just be one coordinated write. So there isn't a whole giant interprocess communication storm going on during it. And in the example of moving, it actually doesn't cause any additional file presenter messaging that wouldn't happen anyway. So things like ns file presenter presented item did move to URL actually happen even when this isn't used.
So one last option, and it's pretty interesting in the context of iCloud, is File Coordinator Writing for Merging. And it tells any file presenter of a file that you are about to write that it should write first if there are changes that the user has made in the UI. And then what you do is while you're writing, writing encompasses reading for the purposes of our locking rules, but what you do in your writing is you actually read, and you can do things like conflict detection, which is what iCloud uses. So it uses this option to make sure that before it decides what the most up-to-date thing is for the user, to make sure that it has all the information about what the user has just done in an application while it's open. Thank you.
One last method in NSFileCoordinator worth mentioning is itemAtURL, didMoveToURL. As I mentioned earlier, we deal in what the user thinks of as files. And what this allows us to do, by the way, is handle complicated case where even though it's the same file, its name is actually changed because of file name extensions. So to take advantage of this, you have to tell us when it just happened by invoking it during coordinated writing. And as an example, NSDocument uses this so that in TextEdit, if a document-- a rich text document switches between RTF and RTFD because an attachment has been added to it, it does this so that everything knows that this file that used to be called.RTF is now called.RTFD.
So moving on to NSFilePresenter. So, and this is, you know, there have been plenty of locking mechanisms before. This is sort of the more novel half of file coordination. And it's, the basic concept is your app says what it's showing to the user. And because it's done that, it gets to participate in other processes as coordinated file access. And it actually gets notified of uncoordinated file access, too. So when you're doing things like you have a document open in TextEdit and then you edit it with Emacs at the same time for some reason, NSDocument will actually use NSFilePresenter-- or because it's a file presenter, we'll get notified of that change, even though, of course, Emacs is not gonna be updated to use, you know, coordinated writing anytime soon, I'm sure.
And the way you use it is you register an NSFilePresenter, and it's a protocol, not a class, and it's something that both NSDocument and UIDocument implement. And there are class methods on NSFileCoordinator for registering file presenters. I just simply add and remove file presenter. And what's interesting about this is you always have to invoke the removing method, even in a garbage-collected application. And the problem is that dialog is often too late. It's too indeterminate. So NSDocument, for example, does this in its close method. So after that point, it's not interested in getting any more notifications.
There's a property that you get to implement called presented item URL, and you don't tell file coordination where the file to be presented is. File coordination will ask your file presenter at the right time. And actually on any thread at any time, so notice that this is an atomic property. There's no non-atomic declaration there.
And there's no setter that goes with this, because you don't tell file coordination when the file's moved. Even if you have something in your application that allows the user to move the file, you don't call setPresentedItemAtURL. What you do is you do a coordinated file access for moving that if your app's UI supports that.
Another property is called presented item operation queue, and it's the queue for all the other messages that I'm going to talk about, what queue they get invoked on. So it's very often okay to return NS operation queue main queue, but very often it's not because it's easy to create deadlocks that way as everything fights over the main thread in your application. So NS document actually uses a private queue of its own for receiving these messages. So two kind of advanced things in the NSFilePresenter API are relinquishPresentedItemToReader and relinquishPresentedItemToWriter, and they tell your NSFilePresenter that something wants to read or write the file that you're presenting.
and they are passed a block, and you must invoke the passed-in block quickly because some other process is waiting for it, of course. Thank you. So, and when you do this, you get to pass a block of your own, and it will be called when the reader or writer is done.
So as an example, I'd like to call it a simple example, but if you haven't seen blocks before, nothing is simple at first. But here we have an implementation of a link which presented item to writer, and in this fictional class, this class has a method called waitForWriter on it. And what waitForWriter does is it can do anything. It might block the UI momentarily, hopefully doing something nice with progress indication, or it just might make sure that this file presenter doesn't have any file access of its own already going on. So when relinquish presented item to writer is invoked, this object sends itself wait for writer, and it can do things like stop looking at the file that time.
And one interesting thing to note, sort of an advanced thing in NSDocument, we have this perform asynchronous file access using block. If you're wondering why is all that machinery necessary when we have this even lower level synchronization mechanism, and it's because there are situations where you not only want to don't look at the file, you don't want to even look at the IVARs whose values depend on what's in the file. So that's where perform asynchronous file access using block comes from. You can't make a decision based on a file's modification date if it's in the middle of changing right then. So... With this stuff, you can, you know, make decisions based on the state of the file and then make sure other things don't change the file while you're actually acting on those decisions. So--and this wait for writer is an example of something that could do that.
So when the object's own file access is done, it calls this block that we passed to it, and it passes in another block-- stop waiting. And when that block is invoked, now we can call the writer. We can let the other process go. And when it is done, the reacquirer block that we pass into it is called, and at that point, we can tell our own object to stop waiting. Thank you.
So there are other methods in NSFilePresenter. So first of all, to hear about changes, presented item did change and presented item did move to URL. So that's pretty good. That's pretty simple compared to using something like FS events or VNode dispatch sources, which is actually what some of this is built on. You get these messages, and as their name implies, did, you catch up. And usually this happens while you've relinquished to a writer while your file presenter has given explicit permission to other processes to write, but not always, because, again, not everyone uses file coordination. And when you get a presented item to change just in the middle of nowhere, you know, do the best you can. Just reread the contents of the file. So if, you know, we want more and more people to use file coordination to close the kind of race conditions that can happen when you have to do this.
So a big part of NSFilePresenter, and it's what makes a lot of iCloud work and also autosave, is being able to implement this method, save presented item changes with completion handler. So it's your indication that something wants to read the most up-to-date contents of the file that you're presenting to the user. And if you're doing something like autosaving, like, you know, NSDocument, the support we just added in Lion, yes, now you should save presented item changes. In an older NS Document application that hasn't been updated to use autosaves in place, we don't make it save then. We leave the user with control over when to save. But in the newer stuff, we get to do this. So by the way, the implication there is that autosaving, as was introduced in the last presentation, is actually a pretty important part of being an iCloud application also.
And what you should do when you get this method is save the user's changes, and its document example invokes save to URL of type for save operation, et cetera, et cetera. And you want to be quick about this. So, again, another process is waiting. So this is no time to present UI. It's no time to ask the user if it should be saved. The answer is yes. And, you know, you don't want to block another process while the user, you know, they might not even be looking at that app right then to answer the sheet if you put one up in front of them. So always invoke the completion handler because some other poor process will be blocked until you do.
So getting deleted. So if your file is open and something does a coordinated write that says it's going to delete it, this is the message you'll get. Accommodate presented item deletion with completion handler. And for example, NSDocument-- I don't think it does this in the C that you have, but it will. Any second now will actually start closing the document. So if it's open and it's in the trash and the user empties the trash-- the user dragged the document into the trash. They went to empty the trash. were asked, do you really want to delete this? At that point, it's safe to really close the document if the user says yes to empty the trash.
So, and again, this is not a good time to present UI. It's a good time to remove UI, but not a good time to ask the user a question. And again, don't forget that completion handler, 'cause you will leave some other process blocked if you don't, at least until your own process ends.
So versions, in the last talk, the NSDocument autosaving and versions presentation right before this one, you learned that we have an NSFileVersion class, and it's very cool. We also have a way to notify you if you're an NSFilePresenter of versions being added or removed to the file that you are presenting with methods like this. Presented item did gain version and did lose version.
And something really just for iCloud is the presented item did resolve conflict version method. What iCloud does is when it detects a conflict, it doesn't even really try to resolve it for you. It just detects it. It picks a winner, and it leaves the winning document contents in the file.
And it picks the loser, and it makes what's called a conflict version out of it. And then it uses file coordination in such a way that the application gets a notification that this conflict-losing version was added. And this is how you take care of it. And, of course, in NSDocument, we've pretty much taken care of it for you. We put you in the versions browser, and we indicate where this came from and stuff like that. So if you're not using NSDocument, for example, you'll probably need to-- if you're not using NSDocument or UIDocument, you'll probably need to learn these.
So supporting iCloud, the last topic to talk about. So I keep talking about NSDocument does this for you automatically. UIDocument does this automatically for you. But not all apps are document-based. So a bit of terminology that we keep throwing around. I don't think marketing likes it very much, but none of us engineers have thought of a better word, so we keep calling it these. What is a shoebox application? Well, it's an application that does not deal in documents. It just shows the user their data. not files, and popular examples are iPhoto and iTunes. You can look at the files that your pictures or music are stored in, but in general, you don't. You just use the UI that it puts up for you. So, and the name comes from this because it's like a shoebox of pictures or tapes.
So using NSFilePresenter in shoebox apps, you can do it. So NSFilePresenter, the name, it has the word file in its name, but that's okay. Just like NSFileManager, NSFileWrapper, it applies to both directories and files, and you can use it when you're presenting a directory full of files, not just one file. So in a particularly interesting kind of directory are what's called iCloudWeek packages, and it's a directory with a specific file name extension W-E-A-K-P-K-G. It doesn't matter much that this is a little unattractive as far as file name extensions go because users aren't supposed to ever see them, right? When you're talking about a shoebox app like iTunes or iPhoto, the user doesn't dig around in the files. So something like this for iCloud, you know, it'll be deep in the user's library folder. So in iCloud, we'll be digging around in those files and so will your application. Thank you.
And what's interesting about how iCloud uses file coordination in a weak package, and what makes it a weak package, you can almost call it a strong directory, but iCloud promises that when it's seen that any file has changed in that directory, it will read a bunch of files per coordinated read, all the files that it thinks change. It puts them all in one coordinated read. And why that's a good thing is because if you are doing coordinated writes, the results will be that iCloud will be blocked out from reading anything until you're done.
So, and likewise, iCloud, it will change multiple files per coordinated writes. And, you know, which multiple files per coordinated write? Well, the same ones that it read during a coordinated read. So the result, the upshot is, is that your consistency rules become our consistency rules. If you have an application running on one device or Macintosh and it makes a bunch of changes inside one of these weak package files, iCloud will pick them up all as one piece, and when it puts them on your other devices, it will put them where your application running on those other devices can see them all as one piece. So you get to worry less about reading one of your files that points to another files, and it reads the entry that says, this file's here, but the file isn't actually there yet.
And as far as file coordination's locking is concerned, this all comes about from the fact that it's just another kind of file package to it. When you read anything in that file package, nothing else is allowed to write anywhere in that file package while you're doing that. Thank you.
So presenting a package, presenting a directory, like these kind of things that you'll use for shoebox apps that interoperate with iCloud. Many of the regular methods I've already told you about apply. Relinquish presented item to reader and relinquish presented item to writer. You'll get these when iCloud wants to read anything at all in the directory of your stuff, and you get to fend it off if you have something complicated going on in the user interface until you're ready to let it go. And again, and also, save presented item changes with completion handler. You know, when iCloud wants to read, if you want to take the opportunity to make sure everything is completely up to date with what the user has done in the UI, this is your opportunity.
When save presented item changes with completion handlers, invoke. the world. So presenting package sub-items, well, as far as the notifications go, if you have an iCloud directory with a bunch of files in it laid out however you might, You need a more fine-grained notification, really, than just presented item did change. Go dig around in everything, looking to see what iCloud just dropped off for you. So we also have methods like this, presented item, sub-item did appear at URL and did change and did move and accommodate presented sub-item deletion. And what's different about these compared to methods you saw before is that they're messages about individual files. You'll get a URL that indicates that locates a file inside your iCloud directory.
And this doesn't actually work on the seed you have right now, by the way, but it is definitely coming soon. So, you know, the stuff you saw in the earlier NS document talk, most of that is really there. But the support for iCloud directories, not quite yet, but soon. And you'll also need to get notifications about versions of packaged sub-items. So your directory full of stuff that iCloud is digging around in while your app is also. Individual files in one of these iCloud weak packages, one of these directories, have their own versions. So iCloud is doing version detection on a very fine-grained basis. And with these NSFilePresenter methods, you will get notifications about that on a very fine-grained basis. So it did gain version, did lose version, and did resolve conflict version.
So to summarize, we've introduced a bunch of new features in both iOS and Mac OS 10.7 this week. Two in particular, iCloud and autosave, we discovered that we could solve a lot of the problems that they share with one new set of mechanisms for both locking and notification. And we wrapped them up in a class called NSFileCoordinator. And in general, you wanna use it whenever your application is changing files. Um... regardless of-- well, unless, of course, there are the sort of files, you know, temporary directories, things like that. And you want to use NSFilePresenter when showing files to the user, even when the user doesn't know they are files, even when they think that they're looking at their photo library or something like that.
So for more information, Bill Dudney can answer your questions about what we've talked about today. There's the documentation, excellent as always up there including release notes. There are the developer forums, and there are header files with super copious comments. They might not help you understand why things are happening, but they will definitely describe in great detail what happens. So in the foundation framework.
Related session, a lot of these have already happened. What's new in Cocoa, iCloud storage overview, autosave and versions. Tomorrow at 3.15 is storing documents in iCloud using iOS 5, which is mostly about the UI document class that's been added to UIKit. And also on Thursday in Nob Hill, you'll hear about some of this iCloud stuff also and what's new in core data on Mac OS X. Thank you very much. Thank you.