У меня есть класс Notification, который реализует протокол NSCoding.
У меня есть массив уведомлений. Я пытаюсь сохранить уведомления с помощью NSUserDefaults. В моем делегате уведомлений моего приложения есть NSMutableArray, который содержит объекты Notification. Это мой делегат приложения:
+ (void) initialize
{
NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
[defaults registerDefaults: [NSDictionary dictionaryWithObject: [NSKeyedArchiver archivedDataWithRootObject: [NSArray array]] forKey: @"notificationsData"]];
}
- (id) init
{
self=[super init];
if(self)
{
NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
NSData* notificationsData=[defaults objectForKey: @"notificationsData"];
notifications= [[NSKeyedUnarchiver unarchiveObjectWithData: notificationsData]mutableCopy];
}
return self;
}
- (void) applicationWillTerminate:(NSNotification *)notification
{
NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
NSData* notificationsData=[NSKeyedArchiver archivedDataWithRootObject: notifications];
[defaults setObject: notificationsData forKey: @"notificationsData"];
}
В классе Notification текст и заголовок имеют тип NSString (оба для чтения), а дата имеет тип NSDate (также имеет свойство readwrite). Вот как я реализую протокол NSCoding:
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject: date forKey: @"date"];
[aCoder encodeObject: title forKey: @"title"];
[aCoder encodeObject: text forKey: @"text"];
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
self=[super init];
if(self)
{
date=[aDecoder decodeObjectForKey: @"data"];
title=[aDecoder decodeObjectForKey: @"title"];
text=[aDecoder decodeObjectForKey: @"text"];
}
return self;
}
Итак, у меня есть эти проблемы:
- Когда приложение завершается, я получаю EXC_BAD_ACCESS в классе уведомлений, когда пытаюсь кодировать текст с помощью NSKeyedArchiver;
- Уведомления не сохраняются, и при запуске приложения массив всегда равен нулю.
Обновление: с помощью дополнительной отладки я обнаружил, где происходит сбой приложения. Можно увидеть больше кода (я использую табличное представление для отображения данных):
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
{
return [notifications count];
}
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
// Debug
id obj=[[notifications objectAtIndex: row] valueForKey: [tableColumn identifier]];
Class class=[obj class];
// What you see above is just for debug purposes
return [[notifications objectAtIndex: row] valueForKey: [tableColumn identifier]];
}
- (void) tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row=[tableView selectedRow];
if(row >= 0 && row< [notifications count])
[removeButton setEnabled: YES];
else
[removeButton setEnabled: NO];
}
Последний вызываемый метод таков:
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;
Вероятно, проблема в том, что данные каким-то образом повреждены, и значение, возвращаемое этим методом, недействительно. В любом случае приложение не падает в этом методе, а после этого метода.
Если я загружаю два объекта из пользовательских значений по умолчанию, только один объект загружается перед сбоем (поэтому метод вызывается один раз).
Однако я все еще не могу понять настоящую причину сбоя.
Больше кода:
- (IBAction) addNotification :(id)sender
{
Notification* notification=[[Notification alloc]init];
[notification setDate: [datePicker dateValue]];
[notification setText: [textView string]];
[notifications addObject: notification];
[tableView reloadData];
}
- (IBAction)removeNotification:(id)sender
{
[notifications removeObjectAtIndex: [tableView selectedRow]];
[tableView reloadData];
}
addNotification и removeNotification запускаются кнопками.
РЕДАКТИРОВАТЬ: я обнаружил, что не использую ARC, но даже если я включу его, приложение вылетает.