1
votes

I'm working on a document-based application, and I want to use a document package as my file format. To do that, it seems that the NSDocument method I need to override is
-writeToURL:ofType:error:.

It sometimes works, but only under certain conditions. For example, this code works:

- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError
{   
    NSFileWrapper *wrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
    [wrapper addRegularFileWithContents:[@"please work" dataUsingEncoding:NSUTF8StringEncoding] preferredFilename:@"foobar"];
    [wrapper writeToURL:absoluteURL options:NSFileWrapperWritingAtomic originalContentsURL:nil error:outError];

    NSDictionary *metadata = [NSDictionary dictionaryWithObject:@"0.1" forKey:@"Version"];
    NSURL *mdURL = [NSURL fileURLWithPath:[[absoluteURL path] stringByAppendingPathComponent:@"SiteInfo.plist"]];
    [metadata writeToURL:mdURL atomically:YES];

    return YES; 
}

But, this code does not (it's the same as above, but with the NSFileWrapper bit taken out):

- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError
{   
    NSDictionary *metadata = [NSDictionary dictionaryWithObject:@"0.1" forKey:@"Version"];
    NSURL *mdURL = [NSURL fileURLWithPath:[[absoluteURL path] stringByAppendingPathComponent:@"SiteInfo.plist"]];
    [metadata writeToURL:mdURL atomically:YES];

    return YES; 
}

The above code puts this cryptic error into the console ("Lithograph" is the name of my app, and ".site" is the package extension):

NSDocument could not delete the temporary item at file://localhost/private/var/folders/qX/qXL705byGmC9LN8FpiVjgk+++TI/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Lithograph%207)/Untitled%20Site.site. Here's the error:
Error Domain=NSCocoaErrorDomain Code=4 UserInfo=0x10059d160 "“Untitled Site.site” couldn’t be removed."

Do I have to write something to the original URL before I can add other files to the package?

3

3 Answers

4
votes

If you are creating a file wrapper from your document, you should use -fileWrapperOfType:error: instead of -writeToURL:ofType:error:.

You would construct a file wrapper for the Info.plist file, insert it into the folder file wrapper and then return the folder wrapper:

- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
{   
    NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil] autorelease];
    [wrapper addRegularFileWithContents:[@"please work" dataUsingEncoding:NSUTF8StringEncoding] preferredFilename:@"foobar"];
    NSDictionary *metadata = [NSDictionary dictionaryWithObject:@"0.1" forKey:@"Version"];
    NSString* errorDescription = nil;
    NSData* dictionaryData = [NSPropertyListSerialization dataFromPropertyList:metadata format:NSPropertyListBinaryFormat_v1_0 errorDescription:&errorDescription];
    if(!dictionaryData)
    {
        if(!errorDescription)
            errorDescription = @"Unknown error";
        if(outError)
            *outError = [NSError errorWithDomain:@"YourErrorDomain" code:69 userInfo:[NSDictionary dictionaryWithObject:errorDescription forKey:NSLocalizedDescriptionKey]];
        return nil;
    }
    [wrapper addRegularFileWithContents:dictionaryData preferredFilename:@"Info.plist"];
    return wrapper;
}
0
votes

I was able to solve my own problem! By adding this line of code at the top of the method, I'm able to manipulate whatever files I want in the package:

[[NSFileManager defaultManager] createDirectoryAtPath:[absoluteURL path] withIntermediateDirectories:YES attributes:nil error:nil];
-3
votes

writeToURL... method implementations should always create a complete document. Your second version doesn't seem to do that, so I'm not sure why you think it should work.