I have a UIDocument
based app that uses NSFileWrapper
s to store data. The 'master' file wrapper contains many additional directory file wrappers, each of which represents a different page of the document.
When saving a large document for which only a small proportion of one page has been modified, UIDocument
spends a LONG time in the background writing the changes (in writeContents:andAttributes:safelyToURL:forSaveOperation:error:
). Surely it should only be writing out this one small change to the file wrapper... what's taking so long?
My contentsForType:error:
override returns a new directory file wrapper with the contents of the master file wrapper (à la WWDC 2012 Session 218 - Using iCloud with UIDocument):
- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
if (!_fileWrapper) {
[self setupEmptyDocument];
}
return [[NSFileWrapper alloc] initDirectoryWithFileWrappers:[_fileWrapper fileWrappers]];
}
And here's a lovely picture of a stack trace from Time Profiler:
Incidentally, it says ~1.6s in that worker thread to save - in actual run time this equated to about 8 seconds.
Edit:
Is there some way I can check whether the file wrappers require writing to disk or not? Just so I can confirm that I'm not somehow doing something strange like updating every sub file wrapper when I make a small change (although I'm sure I'm not...).
Edit:
I had a further play around with the CloudNotes sample app, and it appears that NSFileWrapper
does implement incremental saving, at least in that case! I tested it by initialising a document with 100 notes, each of which contained about 5MB of data. I did a small edit here and there (a single character change to a text view flags the document as needing saving), and recorded roughly how long each save took. The test is relatively crude (and run on the simulator), but the results were something like this:
- 1st write: ~8000ms
- 2nd write: ~4000ms
- 3rd write: ~300ms
- all subsequent writes: ~40ms
Obviously there are many factors affecting the time it takes, especially since it's saving using file coordination in a background thread, but in general the trend always seems to be this sort of exponential decay, until all writes become really very fast.
But I'm still trying to figure out why this doesn't happen in my app. For a large multi-page document (large, but still many times smaller than the document for the CloudNotes test I performed above) the user can be waiting many seconds for a document to close. I don't want to have to put a spinner up for something that should be practically instantaneous.
contentsForType:error:
(main thread) before writing (background thread). I am only replacing the file wrappers I have changed (when they change). However, I have noticed I'm using a method that looks at all my page file wrappers and sorts them into an ordered array. I think this is messing with NSFileWrapper's lazy loading and causing them to need writing somehow. I'm just implementing an index so that I don't have to do this, and will see what difference it makes. – Merger