NSMutableArray исчезает после уничтожения или перезапуска приложения с помощью NSKeyedArchiver

У меня есть приложение, которое хранит объекты Task (пользовательский класс) внутри класса NSMutableArray. Класс Task соответствует протоколам NSCoding и NSCopying, и я также реализовал методы encodeWithCoder и initWithCoder.

Когда пользователь добавляет новую задачу в NSMutableArray list, я сохраняю массив с помощью NSKeyedArchiver. list заполняет UITableView.

Данные сохраняются, и когда я выхожу из приложения и снова захожу, данные все еще там. Когда я какое-то время использую другое приложение и возвращаюсь, данные все еще там. Однако, когда я «убиваю» приложение в многозадачной задаче управления или перезагружаю устройство, данные исчезают. Вот несколько важных фрагментов кода:

#define kFilename @"epapsTasksFile"

.

- (NSString *)dataFilePath {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    return [documentsDirectory stringByAppendingPathComponent:kFilename];
}

- (void)viewDidLoad {

    NSString *filePath = [self dataFilePath];
    if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        self.list = [[NSKeyedUnarchiver unarchiveObjectWithFile:kFilename] retain];
    }
    else {
        self.list = [NSMutableArray arrayWithCapacity:1];
    }

    ...
}

- (void)applicationWillResignActive:(NSNotification *)notification {
    NSMutableArray *updatedList = [[NSMutableArray alloc] initWithArray:self.list];
    [NSKeyedArchiver archiveRootObject:updatedList toFile:kFilename];
}

Почему мое приложение не сохраняет данные, когда приложение «убито» или перезапускается устройство? Кроме того, может быть интересно отметить, что когда я перезапускаю симулятор iPhone, данные остаются на месте.


person epaps    schedule 13.06.2011    source источник


Ответы (1)


Вам необходимо сохранить данные
([NSKeyedArchiver archiveRootObject:updatedList toFile:kFilename]; в методе делегата applicationWillTerminate, а также сохранить их при завершении.

EDIT: applicationWillTerminate не гарантируется в IOS4.0 и выше.

Лучше всего проверить статус возврата archiveRootObject:toFile: и посмотреть, правильно ли хранятся данные. Как вы поняли, это может быть связано с неправильным путем к файлу.

person Tatvamasi    schedule 13.06.2011
comment
Это, кажется, не работает. Я добавил - (void)applicationWillTerminate:(UIApplication *)application { ... } - и это не сработало. Код внутри ... - это метод NSKeyedArchiver. Можно ли поместить это в класс контроллера или это должно быть в моем классе AppDelegate.m? - person epaps; 14.06.2011
comment
@epaps, вы правы, хотя в документации сказано, что этот метод делегата будет вызываться, похоже, этого не произойдет (в IOS4.0 и выше). Это stackoverflow.com/questions/4967745/ предполагает, что вы не можете этого добиться (сохранить данные при закрытии приложения). Кстати, вы не можете сохранить данные заранее (я не знаю логики вашего приложения, но если вы считаете, что данные важны, вы должны часто сохранять их?) - person Tatvamasi; 14.06.2011
comment
Да, данные часто сохраняются. Я могу выйти из приложения, и все сохраняется. Но когда я его убиваю или перезагружаю устройство, уже сохраненные данные пропадают. - person epaps; 14.06.2011
comment
@epaps, как вы проверяете отсутствие данных? Вы убиваете приложение, когда данные сохраняются? Я только что проверил на устройстве, а также на симуляторе: данные, однажды сохраненные (в файл), сохраняются даже после закрытия приложения или перезапуска устройства. - person Tatvamasi; 14.06.2011
comment
Данные сохраняются, я перемещаюсь по приложению и по телефону и проверяю, что данные все еще в приложении. Затем я убиваю приложение, а затем снова открываю приложение там, где должны появиться данные, а их там нет. Как я уже говорил, это работает, когда я делаю это в симуляторе, но не на своем устройстве. - person epaps; 14.06.2011
comment
Вы проверяете, правильно ли архивированы данные (возвращаемое значение)? Кроме того, когда вы не можете получить доступ к данным, вы уверены, что файла нет? (попробуйте с проводником iPhone и посмотрите, действительно ли данные отсутствуют). Пытался понять, проблема в чтении файла или сохранении файла... - person Tatvamasi; 14.06.2011
comment
Как мне проверить, правильно ли он заархивирован? - person epaps; 14.06.2011
comment
возвращаемое значение (BOOL) archiveRootObject: toFile : - person Tatvamasi; 14.06.2011
comment
В консоли пишет deny file-write-create - person epaps; 14.06.2011
comment
вы звоните archiveRootObject: toFile : из основного потока? - person Tatvamasi; 14.06.2011
comment
Не совсем уверен, что вы имеете в виду под этим. Он вызывается в двух разных классах. - person epaps; 14.06.2011
comment
Кстати, еще одно направление мысли: список (который вы пытаетесь заархивировать, сериализуемый? Если да, не можете ли вы его сериализовать? - person Tatvamasi; 14.06.2011
comment
Итак, я сделал это: BOOL test = [NSKeyedArchiver archiveRootObject:updatedList toFile:kFilename]; NSLog(@"Did it save:%@",test ? @"Yes!" :@"Nope");, и он вернул Нет. Хм. - person epaps; 14.06.2011
comment
Когда я запускаю его на симуляторе, похоже, что он сохраняет файл непосредственно на Macintosh HD, а не в какой-либо папке. - person epaps; 14.06.2011
comment
Можете ли вы опубликовать методы, из которых вы вызываете NSKeyedArchiver archiveRootObject:updatedList toFile:kFilename, и как сериализация? - person Tatvamasi; 14.06.2011
comment
Конечно, здесь: - (void)applicationWillResignActive:(NSNotification *)notification { NSMutableArray *updatedList = [[NSMutableArray alloc] initWithArray:self.list]; BOOL test = [NSKeyedArchiver archiveRootObject:updatedList toFile:kFilename]; NSLog(@"Did it save? %@",test ? @"Yes!" :@"Nope"); } Другой после сохранения и такой же. Я бы предпочел попробовать заставить его работать таким образом, а не пытаться использовать другой метод. - person epaps; 14.06.2011
comment
меня на самом деле интересует другой, какой метод и как он называется? - person Tatvamasi; 14.06.2011
comment
Оказывается, я пытался сохранить его в kFileName, хотя должен был сохранить в filePath (NSString *filePath = [self dataFilePath];). Вы хотите обновить свой ответ, чтобы отразить это? Большое вам спасибо за вашу помощь. - person epaps; 14.06.2011
comment
Еще одна вещь, можете ли вы прокомментировать, является ли это хорошей практикой? self.list = [NSMutableArray arrayWithCapacity:1]; Это в операторе if/else в вопросе. - person epaps; 14.06.2011
comment
Я бы предпочел метод экземпляра initWithCapacity методу класса или сохранил/выпустил метод класса. - person Tatvamasi; 14.06.2011
comment
пожалуйста, проверьте обновленный ответ? написал это вообще ,а не конкретно по вашему вопросу. Это нормально? - person Tatvamasi; 14.06.2011
comment
также взгляните на stackoverflow.com/questions/4288719/serialization- vs-archiving/ для быстрого понимания сериализации и архивирования. - person Tatvamasi; 14.06.2011