Search code examples
cocoansdocumentnsfilewrapper

Using NSFileWrapper in NSDocument made of various files


I'm making a document-based Cocoa app in which the document is dynamic a collection of files (users can add or remove files). In particular, the Save and Open operations should be as fast as possible.

If I understand the documentation correctly, I should use NSFileWrapper and implement fileWrapperOfType:error and readFromFileWrapper:ofType:error:. However, I can't find a complete code example. How should I implement the following methods?

#pragma mark - NSDocument

- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError {
    return nil;
}

- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError {
    return YES;
}

#pragma mark - My methods

- (void) addFileToDocumentFromURL:(NSURL*)fileURL {
    // Add a file to the document given the file URL
}

- (void) removeFileFromDocumentWithName:(NSString*)name {
    // Remove a file from the document given the file name
}

Solution

  • Putting together bits and pieces from the documentation:

    - (NSFileWrapper*) fileWrapperOfType:(NSString *)typeName error:(NSError *__autoreleasing *)outError {
        return self.documentFileWrapper;
    }
    
    - (BOOL) readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError {
        self.documentFileWrapper = fileWrapper;
        return YES;
    }
    
    - (void) addFileToDocumentFromURL:(NSURL*)fileURL {
        NSData* fileData = [NSData dataWithContentsOfURL:fileURL];
        NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:fileData];
        fileWrapper.preferredFilename = [fileURL lastPathComponent];
        [self.documentFileWrapper addFileWrapper:fileWrapper];
        [self updateChangeCount:NSChangeDone];
    }
    
    - (void) removeFileFromDocumentWithName:(NSString*)name {
        NSFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:name];
        if (fileWrapper) {
            [self.documentFileWrapper removeFileWrapper:fileWrapper];
            [self updateChangeCount:NSChangeDone];
        }
    }
    
    - (NSFileWrapper*) documentFileWrapper {
        if (!_documentFileWrapper) { // New document
            _documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        }
        return _documentFileWrapper;
    }