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

Ele*_*que 0 exc-bad-access nsuserdefaults

这是许多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;
Run Code Online (Sandbox Code Playgroud)

}

在Box的encodeWithCoder方法中,它为它的所有数组创建了sereval NSData*对象,就像这样.

NSData* p1archv = [NSKeyedArchiver archivedDataWithRootObject:phase1];  
[aCoder encodeObject:p1archv forKey:@"phase1"];
Run Code Online (Sandbox Code Playgroud)

它加载如下所有内容: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");
    }
Run Code Online (Sandbox Code Playgroud)

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

 boxName = [aDecoder decodeObjectForKey:@"boxName"];
Run Code Online (Sandbox Code Playgroud)

flashcards encodeWithCoder:

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

}

和initWithCoder:

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

return self;
Run Code Online (Sandbox Code Playgroud)

}

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

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

@property (readwrite, copy) NSString* boxName;
Run Code Online (Sandbox Code Playgroud)

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

Fel*_*Cat 6

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

boxName = [aDecoder decodeObjectForKey:@"boxName"]; // AUTORELEASED!!!
Run Code Online (Sandbox Code Playgroud)

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

@property (readwrite, copy) NSString* boxName;
Run Code Online (Sandbox Code Playgroud)

当我使用时:

@property (readwrite, retain) NSString* boxName;
Run Code Online (Sandbox Code Playgroud)

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

self.boxName = [aDecoder decodeObjectForKey:@"boxName"]; // HAVE TO USE self.boxName
Run Code Online (Sandbox Code Playgroud)

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

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

 [boxName autorelease];                                       // to be on the safe side
 boxName = [[aDecoder decodeObjectForKey:@"boxName"] retain]; // no more uglygram
Run Code Online (Sandbox Code Playgroud)

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