2010-03-06 11 views
1

Aidez-moi s'il vous plaît avec le problème suivant:problèmes de mémoire avec NSMutableDictionary, provoquant des fuites de mémoire NSCFDictionary

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

Les mises en fuite dans une autre méthode d'une autre classe, il la méthode getGamesList est appelée, comme ceci:

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

Après cela, il y a beaucoup de fuites qui pointe vers NSCFArray dans la chaîne:

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

dans cette méthode:

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

Je suppose ces choses sont reliées les unes aux autres, mais je ne comprends toujours pas tous les conseils de gestion de la mémoire. Merci beaucoup!

Répondre

1

Il ne semble que vous êtes trop en conservant votre tableau.

Lorsque vous créez le gamesDictionary il est créé avec un nombre de conserver +1. Vous le retenez ensuite (le compte devient +2). Lorsque vous obtenez la valeur en dehors de cette fonction, vous la retenez (le nombre devient +3).

Vous avez raison de dire que si vous créez un objet, vous êtes responsable de la gestion de la mémoire. En outre, lorsque vous obtenez un objet d'une méthode, vous devez le conserver si vous souhaitez le conserver plus longtemps que l'étendue de la fonction. Dans votre cas, vous voulez juste obtenir certaines propriétés de l'objet, vous n'avez donc pas besoin de le conserver.

Voici une suggestion:

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

Ce bit suivant est en désordre. vous créez un nouveau dictionnaire et le conservez. Le dictionnaire original n'est pas auto-libéré, donc le compte n'est pas décrémenté et il traîne toujours. Affectez juste le dictionnaire plutôt que d'en créer un nouveau.

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

Maintenant, dans cette méthode:

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

OUI! Cela a réglé le problème! Merci beaucoup, vous m'avez fait plaisir :) Tout est correct, sauf que le retour [gamesDictionary autorelease]; dans cette construction conduit à une erreur EXC_BAD_ACCESS. Juste utilisé retour gamesDictionary à la place et tout est devenu clair! Merci encore! – lonlywolf

+0

Oui, mon erreur. Vous n'avez pas 'créé' le gamesDictionary, donc vous n'êtes pas responsable de sa gestion de la mémoire, vous n'avez donc pas besoin de l'appeler 'autorelease'. – Abizern

+0

Il semble que c'était juste un sommet d'un iceberg. J'ouvre une nouvelle vue dans laquelle getGamesList est appelée (les fuites de mémoire ne signalent aucune erreur), puis je retourne à la vue parents et obtiens beaucoup de fuites. Ce sont: NSCFArray dans if (! [GamesDictionary valueForKey: date_time]) [gamesDictionary setValue: [Tableau NSMutableArray] forKey: date_time]; et NSCFString dans NSString * date_time = [NSString stringWithFormat: @ "% @,% @", [gameDate objectAtIndex: 0], [gameDate objectAtIndex: 2]]; et NSCFNumber dans NSNumber * _id = [[NSNumber alloc] initWithInt: sqlite3_column_int (instruction, 0)]; :) – lonlywolf

2

N'a pas utilisé de cacao depuis des années (c'est pourquoi je ne peux pas vous dire une réponse exacte: /). Mais je suppose que votre problème est que vous utilisez systématiquement retain sur vos objets.

Depuis le compte de référence de l'objet jamais à 0, tous les dictionnaires sont conservées en mémoire et non libéré.

Essayez de retirer le retain sur [NSArray arrayWithArray] et [NSMutableDictionary dictionaryWithDictionary

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