Почему при сохранении файлов в NSDocument создаются версии одного и того же файла со странными символами в имени?

Я работаю над приложением на основе NSDocument, тип документа которого представляет собой комплект пакетов, содержащий набор файлов. Я сохраняю это так:

- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
{
    if (!self.documentFileWrapper) {
        NSFileWrapper *documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        [self setDocumentFileWrapper:documentFileWrapper];
    }

    NSFileWrapper *defaultWrapper = [self.documentFileWrapper.fileWrappers objectForKey:@"default"];
    if (!defaultWrapper) {
        defaultWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        [defaultWrapper setPreferredFilename:@"someFile.ext"];
        [self.documentFileWrapper addFileWrapper:defaultWrapper];
    }

    [defaultWrapper addRegularFileWithContents: ... some computed content for the file ... preferredFilename:@"someFile.ext"];

    return self.documentFileWrapper;
}

Другими словами, в бандле создайте папку «по умолчанию» и сохраните в ней «someFile.ext» с некоторым содержимым.

Теперь проблема. Когда я смотрю, что на самом деле сохранено на диске, я вижу это:

скриншот

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

Откуда берутся версии ресурсов? Что тут происходит? Есть ли документ, который я должен прочитать?


person Jaanus    schedule 26.02.2014    source источник
comment
+ (BOOL)preservesVersions Возвращаемое значение YES, если принимающий подкласс NSDocument поддерживает версии; иначе НЕТ.   -  person Oleg Sobolev    schedule 03.03.2014
comment
Ну, по крайней мере, я могу подтвердить наличие дополнительных файлов, которые вы перечисляете, даже когда + (BOOL)preservesVersions возвращает НЕТ, независимо от того, что возвращает + (BOOL)autosavesInPlace. Изменение возвращаемых значений этих двух функций влияет на включенные параметры в меню, поэтому они запрашиваются. Я дам вам знать, если я найду что-нибудь еще.   -  person Erhannis    schedule 08.03.2014


Ответы (2)


Хорошо, я думаю, что понял это. Как оказалось, дело было вовсе не в версии. Похоже, вы просто каждый раз добавляли новый файл. Сначала несколько замечаний.

  1. Похоже, вы создаете не файл в пакете, а «каталог, содержащий файл», в пакете. Это то, что вы намеревались сделать?
  2. Кажется, что если каталог «по умолчанию» не существует, вы создаете и используете каталог «someFile.ext», что означает, что в следующий раз он создаст новый каталог со странным префиксом. Однако из вашего скриншота я вижу, что у вас уже есть каталог «по умолчанию», а это значит, что это не ваша проблема.

Теперь ваша актуальная проблема: согласно этой документации, addRegularFileWithContents создает новый файл с вашим предпочтительным именем файла, если только каталог (defaultWrapper) уже не содержит файл с таким именем (в основном). Если он уже есть, он создает новый файл с префиксом. addRegularFileWithContents возвращает идентифицирующую строку, относящуюся к созданному NSFileWrapper (я думаю, это имя файла).

Итак, что происходит, так это то, что каждый раз, когда вы пытаетесь сохранить файл, он видит, что файл с таким именем уже существует, и создает новый файл с префиксом. Один из способов решить эту проблему — сохранить NSString, возвращаемый addRegularFileWithContents, затем, когда вы переходите к сохранению, вы проверяете defaultWrapper и удаляете NSFileWrapper, связанный с сохраненным NSString, если он есть, а затем добавляете файл, как обычно. Я изменил ваш код следующим образом:

@interface TestDocument () // Relevant part of my test class.  Note `wrapperFileName`.

@property (nonatomic, strong) NSFileWrapper *documentFileWrapper;
@property (nonatomic, strong) NSString *wrapperFileName;

@end



- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
{
    if (!self.documentFileWrapper) {
        NSFileWrapper *documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        [self setDocumentFileWrapper:documentFileWrapper];
    }

    NSFileWrapper *defaultWrapper = [self.documentFileWrapper.fileWrappers objectForKey:@"default"];
    if (!defaultWrapper) {
        defaultWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        [defaultWrapper setPreferredFilename:@"default"];
        [self.documentFileWrapper addFileWrapper:defaultWrapper];
    } else if (self.wrapperFileName) {
        [defaultWrapper removeFileWrapper:[[defaultWrapper fileWrappers] objectForKey:self.wrapperFileName]];
    }

    self.wrapperFileName = [defaultWrapper addRegularFileWithContents:[@"blah blah" dataUsingEncoding:NSUTF8StringEncoding] preferredFilename:@"someFile.txt"];
    return self.documentFileWrapper;
}
  1. Я изменил предпочтительное имя файла defaultWrapper на «по умолчанию», как я подозреваю, вы и намеревались.
  2. Я добавил блок if, который удаляет ранее сохраненный файл, если он существовал.
  3. Я сохранил новое имя файла NSFileWrapper для использования в следующий раз в # 2.

После этих изменений программа продемонстрировала ожидаемое поведение: один каталог, содержащий один файл, даже после многократного сохранения. Обратите внимание, что это было верно, даже когда preservesVersions возвращал YES. Я не уверен, где он хранит свои версии, но я их не видел.

person Erhannis    schedule 07.03.2014
comment
Спасибо, как говорится в начале: «Похоже, вы просто каждый раз добавляли новый файл». был правильным, так что это была довольно простая ошибка с моей стороны. Я думал, что добавление файла с таким же именем перезаписывает его, но, очевидно, нет, поэтому я должен удалить дубликаты самостоятельно. / «Похоже, вы создаете не файл в пакете, а «каталог, содержащий файл», в пакете. Это то, что ты собирался сделать? -- да. - person Jaanus; 10.03.2014

Вы можете реализовать -writeSafely… так, чтобы он напрямую вызывал -writeToURL:… Реализовать -writeToURL:… так, чтобы он вызывал -fileWrapperOfType:… и затем записывал это в URL атомарно

то есть вы бы взяли на себя ответственность за атомарное сохранение, заставив NSFileWrapper сделать это. Таким образом, оболочка должна аккуратно отслеживать, где файлы действительно заканчиваются.

Источник

person Danish Iqbal    schedule 09.03.2014