NSKeyedArchiver和NSKeyedUnarchiver与NSMutableArray

Gre*_*ner 6 cocoa objective-c archiving nsmutablearray nskeyedarchiver

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

背景:

我创建了一个小型数据库,它本质上是一个包含自定义对象的NSMutableArray,我们可以将其命名为recordObjects.我设置了数组:

database = [[NSMutableArray alloc] init];
Run Code Online (Sandbox Code Playgroud)

我的自定义对象,名为"recordObject",包含以下变量和inits:

NSString *name;
int       anInt;
Bool      aBool;
Run Code Online (Sandbox Code Playgroud)

我也合成了方法,所以我可以拨打电话:

aString = [[database objectAtIndex:someIndex] name];
Run Code Online (Sandbox Code Playgroud)

并添加了我的控制器类的方法来添加,删除和选择要显示的各个记录.到目前为止,一切都正常,完全符合预期.

接下来,我设置了我的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"];
}
Run Code Online (Sandbox Code Playgroud)

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

[NSKeyedArchiver archiveRootObject:database toFile:myPath];
Run Code Online (Sandbox Code Playgroud)

当我运行程序时,所有内容都可以正常运行.为阵列中的每个记录调用编码器方法,并将文件写入磁盘.使用TextEdit打开文件会显示数据存在(虽然对我来说几乎无法理解).

问题:

这是我陷入困境的地方.

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

database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath];
Run Code Online (Sandbox Code Playgroud)

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

x = [database count];
Run Code Online (Sandbox Code Playgroud)

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

现在,这是一个大问题:

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

aString = [[database objectAtIndex:someIndex] name];
Run Code Online (Sandbox Code Playgroud)

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

Program received signal:  “EXC_BAD_ACCESS”.
sharedlibrary apply-load-rules all
Run Code Online (Sandbox Code Playgroud)

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

作为旁注,我实施的所有内容都来自Stephen G. Kochan的书"Objective-C编程"

任何想法将不胜感激!

Rob*_*ger 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;
}
Run Code Online (Sandbox Code Playgroud)

另一个问题是这一行:

database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath];
Run Code Online (Sandbox Code Playgroud)

这很好,除了两件事:

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

你需要这样做:

database = [[NSKeyedUnarchiver unarchiveObjectWithFile:myPath] mutableCopy];
Run Code Online (Sandbox Code Playgroud)

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

  • 像前面的评论一样,unarchiving一个可变对象会创建一个可变对象,我试了一下.也许这是之前SDK中的一个错误已得到纠正. (2认同)