NSUserDefaults против NSKeyedArchiver - PullRequest
4 голосов
/ 28 июля 2011

Я думаю, что это вопрос новичка об управлении данными.

У меня есть приложение, которое загружает и сохраняет различные текстовые файлы.Я хотел бы дать каждому txt-файлу определенные характеристики, которые не сохраняются в txt-файле, такие как имя, стиль, цвет и т. Д.

До сих пор я имел NSMutableArray * myLibrary, в который я сохранял бывсе эти ссылки.Массив выглядит следующим образом:

  • для каждого текстового файла один объект добавляется в myLibrary
  • , каждый объект содержит несколько строк NSStrings, NSUInteger, BOOL и некоторые NSMutableArrays
  • в моем подклассе для этих объектов я работаю с

    - (id) initWithCoder: (NSCoder *) aDecoder;- (void) encodeWithCoder: (NSCoder *) aCoder;

Теперь мой большой вопрос - это лучший и самый безопасный способсохранить эти данные.До сих пор я работал с NSKeyedArchiver, но пользователи сообщали о потере данных, и был один странный случай, когда синхронизация iTunes якобы приводила к ошибкам в данных.NSUserDefaults какой-либо заставки?Я сохраняю myLibrary.dat каждый раз, когда пользователь вносит изменения, поэтому я не совсем понимаю, почему это не должно быть на 100%.Буду очень признателен за любые советы / предложения / объяснения!

Вот код, с помощью которого я пишу и читаю myLibrary.Dat:

   -(NSString*)documentsDirectory
{
    NSLog(@"documentsDirectory");
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
    return documentsDirectory;
}

-(void)saveLibraryDat {

    NSLog(@"Saving myLibrary.dat...");
    NSString *filePath = [[self documentsDirectory] stringByAppendingPathComponent:@"myLibrary.dat"];
    BOOL succeed = [[NSKeyedArchiver archivedDataWithRootObject:myLibrary] writeToFile:filePath atomically:YES];
    if (!succeed){ // do something  }

}


-(void)loadLibraryDat {

    NSLog(@"loadLibraryDat");
    NSString *filePath = [[self documentsDirectory] stringByAppendingPathComponent:@"myLibrary.dat"];

    self.myLibrary = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

    if (self.myLibrary == nil) {
        NSLog(@"myLibrary.dat empty... set up new one");
        [self setupLibrary];
    } else { NSLog(@"Loading myLibrary.dat successful."); }

}

РЕДАКТИРОВАТЬ: Мои методы кодера выглядяткак это:

 - (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.titleName = [aDecoder decodeObjectForKey:@"titleName"];
        self.fileName = [aDecoder decodeObjectForKey:@"fileName"];
        self.fileFont = [aDecoder decodeObjectForKey:@"fileFont"];
 self.tabTitles = [aDecoder decodeObjectForKey:@"tabTitles"];
   }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:titleName forKey:@"titleName"];
    [aCoder encodeObject:fileName forKey:@"fileName"];
    [aCoder encodeObject:fileFont forKey:@"fileFont"];
    [aCoder encodeObject:tabTitles forKey:@"tabTitles"];
}

@end

в заголовке они определены как:

NSString *titleName;
NSString *fileName;
NSString *fileFont;
NSMutableArray *tabTitles;

Ответы [ 3 ]

3 голосов
/ 28 июля 2011

Не используйте NSUserDefaults. Это больше для настроек по умолчанию, например, я должен отображать окно X при запуске. NSUserDefaults не предназначен для данных программы. Вы должны использовать NSKeyArchiver, как вы делаете. Ошибка наиболее вероятна в объектах, которые содержит myLibrary.

Вы должны взглянуть (или опубликовать) функции:

- (id)initWithCoder:(NSCoder *)coder 
- (void)encodeWithCoder:(NSCoder *)coder

Это наиболее вероятно, где ваша проблема лежит.

1 голос
/ 28 июля 2011

Пользователи могут получить доступ к каталогу документов под iOS5 и под любой версией, если они используют взломанные телефоны.Вместо этого сохраните ваши файлы в ~/Library/Application Support/appname.

NSMutableString *path = [[NSMutableString alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSApplicationSupportDirectory, NSUserDomainMask, YES);
[path appendString: [paths objectAtIndex: 0]];
[path appendString: @"/YOURAPPNAME"];

edit

Код, который вы разместили, работает нормально, и проблем не должно быть, если ваш массив содержит типы данных, поддерживаемые NSCoding.В качестве стиля я бы использовал константу в качестве ключа, чтобы избежать глупых опечаток в ключах.Например: NSString *const kTitleName = @"kTitleName"; над вашим разделом @implementation.

0 голосов
/ 09 января 2016

Как уже упоминали другие, NSKeyedArchiver - лучшее решение, чем NSUserDefaults, учитывая, что вы храните данные приложения, а не простые настройки по умолчанию.

Относительно проблемы потери данных ...

Пользователи могутпотерять данные в случае сбоя приложения между временем ввода данных и успешным вызовом saveLibraryDat.Вы можете попробовать что-то вроде Crashlytics для мониторинга сбоев приложений конечного пользователя.

Пользователи также могут потерять данные, если succeed в saveLibraryDat было ложно.Замените // do something значимой обработкой ошибок.Возможно, на устройстве не осталось места для сохранения данных.

...