1

简洁版本:

我定义了一个属性,(nonatomic, retain)并假设该属性将被保留。但除非我retain在为属性分配字典时调用,否则应用程序会因EXEC BAD ACCESS错误而崩溃。

长版:

我有一个有字典的单身人士。标头是这样定义的

@interface BRManager : NSObject {
}

@property (nonatomic, retain) NSMutableDictionary *gameState;

+ (id)sharedManager;
- (void) saveGameState;

@end

在实现文件中,我有一个在 init 中调用的方法。此方法从捆绑包中加载 plist,并在设备上的用户文档文件夹中制作一份副本。

- (void) loadGameState
{
 
    NSFileManager *fileManger=[NSFileManager defaultManager];
    NSError *error;
    NSArray *pathsArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString *doumentDirectoryPath=[pathsArray objectAtIndex:0];
    NSString *destinationPath= [doumentDirectoryPath stringByAppendingPathComponent:@"gameState.plist"];
    NSLog(@"plist path %@",destinationPath);    
    
    if (![fileManger fileExistsAtPath:destinationPath]){
        
        NSString *sourcePath=[[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:@"gameStateTemplate.plist"];
        [fileManger copyItemAtPath:sourcePath toPath:destinationPath error:&error];
        
        gameState = [NSMutableDictionary dictionaryWithContentsOfFile:sourcePath];
                
    }else{
        gameState = [NSMutableDictionary dictionaryWithContentsOfFile:destinationPath];
    }
    
}

现在这就是我认为这应该如何工作。在标题中,我使用(非原子,保留)定义了 gameState 属性。我假设(可能是错误的)“保留”意味着将保留 gameState 字典。但是,我的单例(saveGameState)中有另一种方法,当 AppDelegate -> ' applicationWillResignActive' 时调用它。

- (void) saveGameState
{
    NSArray *pathsArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString *doumentDirectoryPath=[pathsArray objectAtIndex:0];
    NSString *plistPath = [doumentDirectoryPath stringByAppendingPathComponent:@"gameState.plist"];
    [gameState writeToFile:plistPath atomically:YES];
}

这会EXEC BAD ACCESSgameState. 如果我修改 loadGameState 以保留 gameState 字典,则一切正常。例如:

gameState = [[NSMutableDictionary dictionaryWithContentsOfFile:sourcePath] retain];

我猜这是正确的行为,但为什么呢?(nonatomic, retain)并不意味着我认为的意思,或者这里有其他东西在起作用?

我还没有真正了解内存管理,所以我一直偶然发现这些东西。

4

2 回答 2

6

您必须使用访问器:

self.gameState = [NSMutableDictionary dictionaryWithContentsOfFile:sourcePath];

或(相当于):

[self setGameState:[NSMutableDictionary dictionaryWithContentsOfFile:sourcePath]];

代替

gameState = [NSMutableDictionary dictionaryWithContentsOfFile:sourcePath];

它只设置 ivar 而没有任何属性概念。

于 2012-05-03T10:31:55.817 回答
0

您在哪里将 gameState 声明为 ivar?我假设您在实施中这样做。

真正的问题是,在您的实现中,您直接访问 gameState 而实际上并没有调用您声明的属性。为此,您必须向自己发送适当的消息:

[self gameState]; // invokes the synthesized getter
[self setGameState:[NSMutableDictionary dictionaryWithContentsOfFile:sourcePath]]; // invokes the synthesized setter -- solves your problem

或者

whatever = self.gameState; // invokes the getter
self.gameState = [NSMutableDictionary dictionaryWithContentsOfFile:sourcePath]; // invokes the synthesized setter -- solves your problem

确保你有时间去探索内存管理文献......这是一个非常基本的问题,根据 StackOverflow 的严格规则,我不应该回答。祝你好运!

于 2012-05-03T10:37:02.387 回答