1

请帮我解决以下问题:

- (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 @"";
}

我假设这些东西是相互关联的,但我仍然无法理解所有的内存管理技巧。非常感谢!

4

2 回答 2

2

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

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

尝试删除retainon[NSArray arrayWithArray][NSMutableDictionary dictionaryWithDictionary

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

于 2010-03-06T09:26:02.700 回答
1

看起来您确实过度保留了阵列。

当您创建gamesDictionary它时,它的保留计数为 +1。然后你保留它(计数变为+2)。当您获得此函数之外的值时,您会再次保留(计数变为 +3)。

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

这是一个建议:

- (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; 
}

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

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 @"";
}
于 2010-03-06T11:02:27.317 回答