6

我希望这与我在这里使用 Mutable 数组这一事实无关,但这让我感到困惑,所以如果是这样的话,我不会感到惊讶。

背景:

我制作了一个小型数据库,它本质上是一个包含自定义对象的 NSMutableArray,我们可以将其称为 recordObjects。我设置了数组:

database = [[NSMutableArray alloc] init];

我的自定义对象,称为“recordObject”包含以下变量和初始化:

NSString *name;
int       anInt;
Bool      aBool;

我还合成了方法,因此我可以进行如下调用:

aString = [[database objectAtIndex:someIndex] name];

并向我的控制器类添加了方法来添加、删除和选择要显示的单个记录。到目前为止,一切都按预期正常工作。

接下来,我设置了我的 recordObject 类(NSObject 的子类)以使用 NSCoder(通过包含在 @interface 指令中,并在实现文件中添加了以下自定义编码器和解码器方法:

-(void) encodeWithCoder: (NSCoder *) encoder {
    [encoder encodeObject: name  forKey: @"recordName"];
    [encoder encodeInt:    anInt forKey: @"recordInteger"];
    [encoder encodeBool:   aBool forKey: @"recordBool"];
}

-(id) initWithCoder: (NSCoder *) decoder {
    name    = [decoder decodeObjectForKey: @"recordName"];
    anInt   = [decoder decodeIntForKey:    @"recordInteger"];
    aBool   = [decoder decodeBoolForKey:   @"recordBool"];
}

为了编写文件,我使用了以下内容:

[NSKeyedArchiver archiveRootObject:database toFile:myPath];

当我运行程序时,一切似乎都正常工作。为数组中的每条记录调用编码器方法,并将文件写入磁盘。用 TextEdit 打开文件显示数据在那里(虽然对我来说大多难以理解。)

问题:

这是我遇到障碍的地方。

我添加了以下代码以将文件加载到我的数据库数组中:

database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath];

当我再次运行程序时,这次加载数据库,它似乎可以正常工作。我的第一个测试是使用 NSMutableArray 计数方法:

x = [database count];

结果是 X 填充了文件中正确数量的记录。如果我保存数据库时有 5 条记录,则在下次执行程序时加载数据库后将 X 设置为 5。

现在,这是一个大问题:

如果我尝试使用我的任何访问器方法,程序就会崩溃。例如,如果我在加载数据库后尝试使用以下内容:

aString = [[database objectAtIndex:someIndex] name];

程序崩溃并在控制台中返回以下错误:

Program received signal:  “EXC_BAD_ACCESS”.
sharedlibrary apply-load-rules all

我的解释是,由于某种原因,数据没有正确加载和初始化到数据库数组中,但是对于我的生活,我无法弄清楚我在哪里出错了。

附带说明一下,我实现的所有内容都来自 Stephen G. Kochan 的《Objective-C 编程》一书

任何想法将不胜感激!

4

4 回答 4

14

您的代码存在一些问题。

你的initWithCoder:方法没有完全实现。您必须调用[super init]并返回self。您还必须copyretain字符串对象,否则它将被自动释放:

- (id)initWithCoder:(NSCoder *)decoder 
{
    self = [super init];
    if(self)
    {
         name    = [[decoder decodeObjectForKey: @"recordName"] copy];
         anInt   = [decoder decodeIntForKey:    @"recordInteger"];
         aBool   = [decoder decodeBoolForKey:   @"recordBool"];
    }
    return self;
}

另一个问题是这一行:

database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath];

这很好,除了两件事:

  1. 您没有持有对该对象的引用,因此它将被自动释放。
  2. NSKeyedArchiver返回一个不可变对象,在这种情况下是 anNSArray而不是 an NSMutableArray

你需要这样做:

database = [[NSKeyedUnarchiver unarchiveObjectWithFile:myPath] mutableCopy];

这将保留对象(因为它是副本)并使对象成为NSMutableArray.

于 2012-04-30T23:57:16.190 回答
4

您似乎没有在 -initWithCoder 中初始化记录对象:

尝试这样的事情:

-(id) initWithCoder: (NSCoder *) decoder {

    self = [super init];

    if (self){

       name    = [decoder decodeObjectForKey: @"recordName"] copy];
       anInt   = [decoder decodeIntForKey:    @"recordInteger"];
       aBool   = [decoder decodeBoolForKey:   @"recordBool"];
     }

    return self;
}

存档时数据就在那里,但您没有正确取消存档。

于 2012-04-30T23:28:25.830 回答
2

对我来说听起来像是内存管理问题。EXC_BAD_ACCESS通常意味着您正在尝试访问已被释放的对象。unarchiveObjectWithFile:返回一个自动释放的对象,因此如果要保留它,则必须保留它,无论是使用显式retain还是通过将其分配给保留属性。

于 2012-04-30T23:26:47.267 回答
0

取消归档自定义对象时我遇到了同样的问题

self.calTable = [[NSKeyedUnarchiver unarchiveObjectWithFile:calibrationFile] objectForKey:@"calTable"];

根据 Rob 的回答,我改为

self.calTable = [[[NSKeyedUnarchiver unarchiveObjectWithFile:calibrationFile] mutableCopy] objectForKey:@"calTable"];

它修复了所有错误。

于 2014-08-07T19:12:39.030 回答