0

我有一个实现 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;
}

所以我有这些问题:

  1. 当应用程序终止时,当我尝试使用 NSKeyedArchiver 对文本进行编码时,我在 Notification 类中得到 EXC_BAD_ACCESS;
  2. 通知不会被保存,并且当应用程序启动时数组总是长零。

更新:通过更多调试,我发现了应用程序崩溃的位置。还有更多代码可以查看(我正在使用表格视图来显示数据):

- (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,但即使我打开它,应用程序也会崩溃。

4

3 回答 3

2

在行中:

date=[aDecoder decodeObjectForKey: @"data"];

@"data"与编码器键不匹配。你真的想要:

date=[aDecoder decodeObjectForKey: @"date"];
于 2012-10-29T18:32:08.407 回答
1

您可能需要调用 [NSUserDefaults synchronize] 因为当应用程序突然退出时它不会自动发生:

- (void) applicationWillTerminate:(NSNotification *)notification
{
    NSUserDefaults* defaults=[NSUserDefaults standardUserDefaults];
    NSData* notificationsData=[NSKeyedArchiver archivedDataWithRootObject: notifications];
    [defaults setObject: notificationsData forKey: @"notificationsData"];
    [defaults synchronize];
}
于 2012-10-29T17:54:59.793 回答
0

你猜不出哪里出了问题:我的错,我忘记启用 ARC 并且一些对象在不应该的时候被释放了。

于 2012-10-30T15:27:20.930 回答