NSCodingプロトコルを実装するクラスNotificationがあります。
通知の配列があります。NSUserDefaultsを使用して通知を保存しようとしています。アプリのデリゲート通知には、通知オブジェクトを含むNSMutableArrayがあります。これがアプリのデリゲートです。
+ (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です(これにも読み取り/書き込みプロパティがあります)。これは、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;
}
だから私はこれらの問題を抱えています:
- アプリケーションが終了すると、NSKeyedArchiverを使用してテキストをエンコードしようとすると、NotificationクラスでEXC_BAD_ACCESSが取得されます。
- 通知は保存されず、アプリケーションの起動時に配列は常にロングゼロになります。
更新:より多くのデバッグで、アプリケーションがクラッシュする場所を発見しました。表示するコードがさらにあります(データを表示するためにテーブルビューを使用しています):
- (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;
おそらく問題は、データが何らかの理由で破損していて、このメソッドによって返される値が無効であるということです。とにかく、アプリはこのメソッドではクラッシュしませんが、このメソッドの後でクラッシュします。
ユーザーのデフォルトから2つのオブジェクトをロードすると、クラッシュする前に1つのオブジェクトのみがロードされます(したがって、メソッドは1回呼び出されます)。
しかし、私はまだクラッシュの本当の理由を知ることができません。
その他のコード:
- (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を使用していないことを発見しましたが、それをオンにしてもアプリがクラッシュします。