• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
NSDocument packages and incremental writing using NSFileWrapper
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

NSDocument packages and incremental writing using NSFileWrapper


  • Subject: NSDocument packages and incremental writing using NSFileWrapper
  • From: Thomas Zoechling <email@hidden>
  • Date: Wed, 30 Jan 2013 16:53:35 +0100

Hello,

My NSDocument based app uses packages with the following structure:

- document.package
+- metadata.plist (small, mutable)
+- large0.file (large, immutable)
+- large1.file (large, immutable)
+- large2.file (large, immutable)

While the metadata.plist file can change any time, all large files are created once and then stay as they are.
As my "large0-2" files can be several gigabytes, I try to carefully avoid unnecessary IO by using document packages with NSFileWrapper.
My package reading/writing methods resemble the ones in the "Document Package with iCloud" sample (But I don't use iCloud): http://developer.apple.com/library/mac/#samplecode/PackagedDocument/
I appended the relevant parts of my code at the end of this message.

With this setup, I was hoping that the occasions where the document architecture has to copy the whole bundle are reduced to:
- File duplication
- Moves to another volume

But after investigating file activity with Instruments.app, it turned out that my app is reading and writing chunks of my unmodified, immutable & large files during each save.
It seems that the copying is related to document revisions (a.k.a. Versions).
Instruments logs hundreds of IO operations in the form of:
#	Caller	Function	FD	Path	Bytes
...
70	copyfile	read	22	document.package/large0.file	1048576
71	copyfile	write	23	/.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file	1048576
70	copyfile	read	22	document.package/large0.file	1048576
71	copyfile	write	23	/.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file	1048576
70	copyfile	read	22	document.package/large0.file	1048576
71	copyfile	write	23	/.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file	1048576
...

How can I tell Versions that the only file that constantly changes within my document.package is metadata.info? (Without turning off document revisions altogether)
I am targetting 10.8 (with sandboxing enabled) and also adopted async saving and autosavesInPlace.

with kind regards,
Thomas

---

- (NSFileWrapper*)fileWrapperOfType:(NSString*)typeName error:(NSError**)outError
{
    if([self documentFileWrapper] == nil)
    {
        NSFileWrapper* documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        [self setDocumentFileWrapper:documentFileWrapper];
        [documentFileWrapper release];
    }
    NSURL* documentURL = [self fileURL] == nil ? [self autosavedContentsFileURL] : [self fileURL];
    if(documentURL)
    {
        //Check if we already have a metadata file wrapper. If "YES" remove it.
        NSFileWrapper* previousRecordingInfoFileWrapper = [[[self documentFileWrapper] fileWrappers] objectForKey:kSSWInfoPlistFilename];
        if(previousRecordingInfoFileWrapper != nil)
        {
            [[self documentFileWrapper] removeFileWrapper:previousRecordingInfoFileWrapper];
        }
        NSData* recordingInfoData = [NSPropertyListSerialization dataFromPropertyList:recordingInfoDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&serializationErrorDescriptions];
        [self unblockUserInteraction];
        NSFileWrapper* recordingInfoFileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:recordingInfoData];
        [recordingInfoFileWrapper setPreferredFilename:kSSWInfoPlistFilename];
        [[self documentFileWrapper] addFileWrapper:recordingInfoFileWrapper];
        [recordingInfoFileWrapper release];
        if(([[[self documentFileWrapper] fileWrappers] objectForKey:kSSWRecordingFrameName] == nil))
        {
            NSFileWrapper* frameFileWrapper = [[NSFileWrapper alloc] initWithURL:[documentURL URLByAppendingPathComponent:kSSWRecordingFrameName] options:0 error:outError];
            [frameFileWrapper setPreferredFilename:kSSWRecordingFrameName];
            [[self documentFileWrapper] addFileWrapper:frameFileWrapper];
            [frameFileWrapper release];
        }
		...
	}
}

- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError
{
    BOOL didRead = NO;
    NSFileWrapper* recordingInfoWrapper = [[fileWrapper fileWrappers] objectForKey:kSSWInfoPlistFilename];
    if(!recordingInfoWrapper)
    {
        NSMutableDictionary* errorDetail = [NSMutableDictionary dictionary];
        NSString* errorDescription = NSLocalizedString(@"Could not open recording.\nThe recording is missing it's metadata file.", @"Displayed when trying to open a corrupted bundle");
        [errorDetail setValue:errorDescription forKey:NSLocalizedDescriptionKey];
        if(outError)
        {
            *outError = [NSError errorWithDomain:kSSWRecordingErrorDomain code:100 userInfo:errorDetail];
        }
    }
    else
    {
        NSDictionary* recordingInfoDict = [NSPropertyListSerialization propertyListWithData:[recordingInfoWrapper regularFileContents] options:0 format:nil error:outError];
        if(recordingInfoDict)
        {
			self.recordingInfo = recordingInfoDict;
        }
    }
    [self setDocumentFileWrapper:fileWrapper];
    return didRead;
}


_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: NSDocument packages and incremental writing using NSFileWrapper
      • From: Mike Abdullah <email@hidden>
  • Prev by Date: NSTableView and performClickOnCellAtColumn - cannot make it work
  • Next by Date: Re: Localization not working based on region with en-US, en-UK and en lproj
  • Previous by thread: Re: NSTableView and performClickOnCellAtColumn - cannot make it work
  • Next by thread: Re: NSDocument packages and incremental writing using NSFileWrapper
  • Index(es):
    • Date
    • Thread