基于NSDocument的Mac应用程序与文件捆绑,超级慢保存

时间:2013-05-27 12:34:35

标签: cocoa bundle nsdocument

所以在谷歌搜索后,我的理解是,当我在基于NSDocument的应用程序中使用捆绑包作为我的文档时,我每次要保存时都必须编写整个捆绑包?由于我正在向文档中添加大量视频文件,因此这开始出现问题。

有没有办法解决这个问题而不抛弃NSDocument?

2 个答案:

答案 0 :(得分:11)

使用文档包的一个优点是每次保存时都不需要编写所有内容。您应该向documentFileWrapper子类添加NSDocument属性,当文档体系结构读入文档包时,您应该在该属性中存储NSFileWrapper引用,并且还应该跟踪改变了什么。例如,aAssuming您在文档包中保留了文本文件和视频文件:

@interface MyDocument ()
    @property (nonatomic, copy) NSString *text;
    @property (nonatomic, assign) bool textHasChanged;

    @property (nonatomic, copy) NSData *videoData;
    @property (nonatomic, assign) bool videoHasChanged;

    @property (nonatomic, strong) NSFileWrapper *documentFileWrapper;
@end

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


    // Read the contents of file wrapper
    // …

    [self setDocumentFileWrapper:fileWrapper];

    return YES;
}

如果从磁盘读取文档包,documentFileWrapper将保留对该包的引用。如果是新文档,则documentFileWrappernil

保存文档时,重用documentFileWrapper并仅写入需要保存的文件。如果文档尚未保存(这是一个新文档),documentFileWrappernil,那么您需要创建一个:

- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName
                               error:(NSError **)outError
{

    if ([self documentFileWrapper] == nil) {
        NSFileWrapper *documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:@{}];
        [self setDocumentFileWrapper:documentFileWrapper];
    }

    NSDictionary *fileWrappers = [[self documentFileWrapper] fileWrappers];
    NSFileWrapper *textFileWrapper = [fileWrappers objectForKey:@"text.txt"];
    NSFileWrapper *videoFileWrapper = [fileWrappers objectForKey:@"video.mp4"];

    if ((textFileWrapper == nil && [self text] != nil) || [self textHasChanged]) {
        if (textFileWrapper != nil)
            [documentFileWrapper removeFileWrapper:textFileWrapper];

        if ([self text] != nil) {
            NSData *textData = [[self text] dataUsingEncoding:NSUTF8StringEncoding];
            [documentFileWrapper addRegularFileWithContents:textData preferredFileName:@"text.txt"];
        }
    }

    if ((videoFileWrapper == nil && [self videoData] != nil) || [self videoHasChanged]) {
        if (videoFileWrapper != nil)
            [documentFileWrapper removeFileWrapper:videoFileWrapper];

        if ([self videoData] != nil)
            [documentFileWrapper addRegularFileWithContents:[self videoData] preferredFileName:@"video.mp4"];
    }

    return documentFileWrapper;
}

在上面的代码中,仅当文档包(文件包装器)尚不存在时才会创建它。换句话说,仅当文档是新文档且尚未保存时才会创建它。创建包后,其引用存储在documentFileWrapper

接下来,我们检查是否需要编写文本文件。它写成如果:     *要么还没有文本文件(可能因为它是一个新的包)而且我们有实际的文本要写;     *或文本已被更改。

我们对视频文件也这样做。

请注意,如果文档已从磁盘加载或至少保存一次,则视频文件将添加到包中(并且以前的视频文件,如果有的话,从包中删除)仅在视频数据已被删除时改变。

注意:这个答案假定ARC和自动属性合成(ivar名称前缀为下划线)。

答案 1 :(得分:4)

我知道这已经得到了解答,但作为参考,如果您查看Apple的Packaged Document示例代码,您会看到一个有效的变体,而无需保留changed标志对于每个实例变量。

基本理念是:

  • 如果模型变量发生更改,请从主文件包装器中删除相应的文件包装器
  • fileWrapperOfType:…中构建文件包装器时,只添加缺少的文件包装(即已更新)