NSMutableDictionary存在内存问题,导致NSCFDictionary内存泄漏

时间:2010-03-06 08:43:01

标签: cocoa memory nsmutabledictionary memory-leaks

请帮我解决以下问题:

- (NSDictionary *)getGamesList
{
    NSMutableDictionary *gamesDictionary = [[NSMutableDictionary dictionary] retain];
// I was trying to change this on the commented code below, but did have no effect
//    NSMutableDictionary *gamesDictionary = [[NSMutableDictionary alloc] init];
//    [gamesDictionary retain];
    while (sqlite3_step(statement) == SQLITE_ROW)
    {
        NSString *key = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
        NSArray *gameDate = [key componentsSeparatedByString:@" "];
        NSNumber *_id = [[NSNumber alloc] initWithInt:sqlite3_column_int(statement, 0)];
        NSString *date_time = [NSString stringWithFormat:@"%@, %@",[gameDate objectAtIndex:0],[gameDate objectAtIndex:2]];
        if (![gamesDictionary valueForKey:date_time]) [gamesDictionary setValue:[NSMutableArray array] forKey:date_time];
        [[gamesDictionary valueForKey:date_time] addObject:[[_id copy] autorelease]];
        [_id release];
    }
    sqlite3_reset(statement);
    return gamesDictionary;
}

泄漏从另一个类的另一个方法开始,在那里调用getGamesList方法,如下所示:

NSMutableDictionary *gamesDictionary;
gamesDictionary = [[NSMutableDictionary dictionaryWithDictionary:[appDelegate getGamesList]] retain];

之后有很多泄漏指向字符串中的NSCFArray:

NSArray *keys = [[NSArray arrayWithArray:[gamesDictionary allKeys]] retain]; 

在这种方法中:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSArray *keys = [[NSArray arrayWithArray:[gamesDictionary allKeys]] retain];
    if ([keys count] != 0)    return [[keys objectAtIndex:section] uppercaseString];
    return @"";
}

我认为这些东西是相互连接的,但我仍然无法理解所有的内存管理技巧。 非常感谢!

2 个答案:

答案 0 :(得分:2)

多年来没有使用Cocoa(这就是为什么我不能告诉你一个确切的答案:/)。但我想您的问题是您系统地在对象上使用retain

由于对象引用计数永远不会为0,因此所有字典都保留在内存中而不会被释放。

尝试删除retain[NSArray arrayWithArray]

上的[NSMutableDictionary dictionaryWithDictionary

http://en.wikibooks.org/wiki/Programming_Mac_OS_X_with_Cocoa_for_beginners/Some_Cocoa_essential_principles#Retain_and_Release

答案 1 :(得分:1)

看起来你过度保留了阵列。

创建gamesDictionary时,会创建保留计数为+1的- (NSDictionary *)getGamesList { NSMutableDictionary *gamesDictionary = [NSMutableDictionary dictionary]; // Remove the retain. while (sqlite3_step(statement) == SQLITE_ROW) { NSString *key = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)]; NSArray *gameDate = [key componentsSeparatedByString:@" "]; NSNumber *_id = [[NSNumber alloc] initWithInt:sqlite3_column_int(statement, 0)]; NSString *date_time = [NSString stringWithFormat:@"%@, %@",[gameDate objectAtIndex:0],[gameDate objectAtIndex:2]]; if (![gamesDictionary valueForKey:date_time]) [gamesDictionary setValue:[NSMutableArray array] forKey:date_time]; [[gamesDictionary valueForKey:date_time] addObject:[[_id copy] autorelease]]; [_id release]; } sqlite3_reset(statement); return gamesDictionary; } 。然后保留它(计数变为+2)。当您获得此功能之外的值时,您将再次保留(计数变为+3)。

你是对的,如果你创建一个对象,你负责它的内存管理。此外,当您从方法中获取对象时,如果要将其保留的时间超过函数的范围,则应保留该对象。在你的情况下,你只想获得对象的一些属性,所以你不需要保留它。

这是一个建议:

NSMutableDictionary *gamesDictionary = [[appDelegate getGamesList] retain];
// Retaining it, becuase it looks like it's used elsewhere.

下一点是凌乱的。你创建一个新的字典并保留它。原始字典不是自动释放的,因此计数不会减少并且它总是挂起。只需分配字典而不是创建新字典。

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSString *returnString;
    // Don't need to retain the keys because you are only using it within the function
    // and since you didn't alloc, copy or retain the array it contains, you aren't responsible for it's memory management.
    NSArray *keys = [NSArray arrayWithArray:[gamesDictionary allKeys]];
    if ([keys count] != 0) {
        returnString = [[NSString alloc] initWithString:[[keys objectAtIndex:section] uppercaseString]];
        return [returnString autorelease];
    }
    return @"";
}

现在,在这个方法中:

{{1}}