在@Property上加载首选项时,应用程序崩溃(EXC_BAD_ACCESS)

时间:2011-05-29 13:40:59

标签: nsuserdefaults exc-bad-access

这是许多EXC_BADACCES问题之一,但我已经做了很长时间的研究,并认为这个问题尚未得到解答。我的应用程序在首选项中保存数据。一切都很好,如果我删除首选项并启动应用程序,那么根本不会发生任何加载。但如果发生加载,就会出现问题。我必须保存一个主数组,其中包含一个名为Box的自写对象。 One Box有一个NSString * boxName和六个NSMutableArray *,它们包含另一个自编写的对象,称为Flashcard,它包含两个NSString *:问题和答案。如果AppDelegate获取消息applicationWillTerminate,它将使用NSKeyedArchiver对主数组(称为boxArray)进行编码,并将其保存在首选项中。在AppControll的init方法中,此归档文件是从首选项加载的:

- (id)init {
self = [super init];
if (self) {
    // Initialization code here.
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    NSData* archive = [defaults objectForKey:@"boxArray"];
    if (archive) {
        NSArray* array = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
        boxArray = [NSMutableArray arrayWithArray:array];
    } else {
    boxArray = [[NSMutableArray alloc] init];
    }

}

return self;

}

在Box的encodeWithCoder方法中,它为其所有数组创建了sereval NSData *对象,如下所示。

NSData* p1archv = [NSKeyedArchiver archivedDataWithRootObject:phase1];  
[aCoder encodeObject:p1archv forKey:@"phase1"];

并加载这样的所有内容:     NSData * p1archv = [aDecoder decodeObjectForKey:@“phase1”];

if (p1archv) {
        NSArray* a = [NSKeyedUnarchiver unarchiveObjectWithData:p1archv];
        phase1 = [NSMutableArray arrayWithArray:a];
        NSLog(@"loaded phase1: %@",phase1);
    } else {
        phase1 = [[NSMutableArray alloc] init];
        NSLog(@"inited phase1");
    }

它保存自己的盒子名称,如下所示:     [aCoder encodeObject:boxName forKey:@“boxName”]; 加载是这样的:

 boxName = [aDecoder decodeObjectForKey:@"boxName"];

flashcards encodeWithCoder:

- (void) encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:question forKey:@"question"];
[aCoder encodeObject:answer forKey:@"answer"];
NSLog(@"encoded %@ and %@",question, answer);

}

和initWithCoder:

- (id) initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
    // Initialization code here.
    question = [aDecoder decodeObjectForKey:@"question"];
    answer = [aDecoder decodeObjectForKey:@"answer"];
}

return self;

}

好的,现在您知道了实际设置,但这就是我的实际问题:

如果应用程序启动,并且有加载首选项,它会在Box.h文件中崩溃。 确切地说,它在这一行中崩溃了:

@property (readwrite, copy) NSString* boxName;

使用EXC_BAD_ACCESS。我打开了NSZombieEnabled并显示了完全相同的一行。 在我的研究中,我在每一种方法都做了制动点,我发现,在使用Box的编码器方法的init中,一切正常,boxName就是它应该是什么(例如“foo”)但是如果是tableview(Managed)通过NSArrayController)想要将数据加载到表视图中,它在运行时崩溃或显示像例如单步执行“1:918”。我确定,我没有在加载过程中发布数组,或者boxName或其他任何东西,所以我无法解释这个问题。如果你能帮助我,我会很高兴,Elefantosque

1 个答案:

答案 0 :(得分:6)

我怀疑你的问题是decodeObjectForKey将始终返回一个自动释放的对象。因此:

boxName = [aDecoder decodeObjectForKey:@"boxName"]; // AUTORELEASED!!!

将一个字符串粘贴到boxName中,最终会消失,然后你会得到一个难看的东西。另外,被定义为这个属性:

@property (readwrite, copy) NSString* boxName;

当我使用时:

@property (readwrite, retain) NSString* boxName;

然后在代码中使用以下内容:

self.boxName = [aDecoder decodeObjectForKey:@"boxName"]; // HAVE TO USE self.boxName

这样做是将字符串保留在boxName中。我的猜测是,如果您更改属性行和分配行,您的错误将消失(尽管您可能有其他人)。

如果您不想更改属性行,则可以使用:

 [boxName autorelease];                                       // to be on the safe side
 boxName = [[aDecoder decodeObjectForKey:@"boxName"] retain]; // no more uglygram

THUMB规则:除非你使用[alloc],否则假定该对象是自动释放的。