Приложение на основе NSDocument Mac с пакетами для документа, очень медленно сохраняющее

Итак, после того, как я немного разобрался в этом, я понял, что когда я использую пакет для своего документа в приложении на основе NSDocument, я должен писать весь комплект каждый раз, когда хочу сохранить? Здесь возникает проблема, так как я добавляю в документ большие видеофайлы.

Есть ли способ обойти это без выброса NSDocument?

2 ответа

Одним из преимуществ использования пакетов документов является то, что вам не нужно писать все каждый раз при сохранении. Вы должны добавить свойство documentFileWrapper к вашему подклассу NSDocument, и, когда архитектура документа читается в пакете документов, вы должны сохранить ссылку NSFileWrapper в этом свойстве, и вы также должны отслеживать, что было изменено. Например, aAssuming youre, сохраняя текстовый файл и видеофайл в пакете документов:

@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 хранит ссылку на этот пакет. Если его новый документ documentFileWrapper равен nil.

При сохранении документа повторно используйте documentFileWrapper и пишите только файлы, требующие сохранения. Если документ еще не сохранен (новый документ), documentFileWrapper - nil, вам нужно создать его:

- (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.

Далее мы проверяем, нужно ли нам писать текстовый файл. Это написано, если:   * либо нет текстового файла (вероятно, потому, что его новый пакет), и у нас есть фактический текст для записи;   * или если текст был изменен.

Мы делаем то же самое для видеофайла.

Обратите внимание, что если документ загружен с диска или сохраняется хотя бы один раз, видеофайл добавляется в пакет (и предыдущий видеофайл, если он есть, удаляется из пакета), только если видеоданные были изменилось.

NB: этот ответ предполагает ARC и автоматический синтез свойств (имена ivar с префиксом подчеркивания).


Я знаю, что на это был дан ответ, но как ссылка, если вы посмотрите на образец Packaged Document, вы увидите вариант, который работает без необходимости поддерживать флаг changed для каждой переменной экземпляра.

Основная идея:

  • Если переменная модели изменяется, удалите ее соответствующую оболочку файла из основной обертки файла
  • При создании файловой оболочки в fileWrapperOfType:… добавьте только те, которые отсутствуют (т.е. были обновлены)

licensed under cc by-sa 3.0 with attribution.