请帮我解决以下问题:
- (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 @"";
}
我认为这些东西是相互连接的,但我仍然无法理解所有的内存管理技巧。 非常感谢!
答案 0 :(得分:2)
多年来没有使用Cocoa(这就是为什么我不能告诉你一个确切的答案:/)。但我想您的问题是您系统地在对象上使用retain
。
由于对象引用计数永远不会为0,因此所有字典都保留在内存中而不会被释放。
尝试删除retain
和[NSArray arrayWithArray]
[NSMutableDictionary dictionaryWithDictionary
答案 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}}