尽管使用(非原子,保留),为什么我必须保留一个属性?

时间:2012-05-03 09:59:42

标签: ios memory-management xcode4.2

简短版本:

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

长版本:

我有一个有字典的单身人士。标题定义如下

@interface BRManager : NSObject {
}

@property (nonatomic, retain) NSMutableDictionary *gameState;

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

@end

在实现文件中,我有一个在init中调用的方法。此方法从包中加载plist,并在设备的users documents文件夹中创建它的副本。

- (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属性。我假设(可能不正确)'retain'意味着将保留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 ACCESS上引发gameState错误。如果我修改loadGameState以保留gameState字典,那么一切都可以正常工作。例如:

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

我猜这是正确的行为,但为什么呢? (nonatomic, retain)是不是意味着我认为它意味着什么,或者是其他什么在这里发挥作用?

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

2 个答案:

答案 0 :(得分:5)

您必须使用访问者:

self.gameState = [NSMutableDictionary dictionaryWithContentsOfFile:sourcePath];

或(相当于):

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

而不是

gameState = [NSMutableDictionary dictionaryWithContentsOfFile:sourcePath];

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

答案 1 :(得分: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

确保你到处寻找memory management literature ...这是一个非常基本的问题,根据StackOverflow的严格规则,我不应该回答。祝你好运!