2011-05-02 4 views
3

J'essaie de réparer une erreur EXC_BAD_ACCESS qui est levée lorsque j'accède à un NSMutableDictionary dans tableView: cellForRowAtIndexPath: indexPath. En ce moment, cela fonctionne quand je remplirai ridesDict avec une méthode loadHistoryFromDBExtended comme ceci:NSMutableDictionary provoquant EXC_BAD_ACCESS

self.ridesDict = [self loadHistoryFromDBExtended]; 

NSLog(@"rides dict %@", self.ridesDict); 

Cependant, je ne veux pas appeler [auto loadHistoryFromDBExtended] pour chaque cellule étant chargé depuis le dictionnaire ne changera pas si j'ai essayé mouvement:

self.ridesDict = [self loadHistoryFromDBExtended]; 

à viewDidLoad et maintenant j'obtiens l'erreur de EXC_BAD_ACCESS quand je l'utilise:

NSLog(@"rides dict %@", self.ridesDict); 

à tableView: cellForRowAtIndexPath: indexPath. D'après ce que j'ai lu, il semble que j'ai des problèmes de mémorisation, mais je n'arrive pas à le comprendre. J'ai essayé [self.ridesDict retain] dans viewDidLoad après l'appel de la méthode loadHistoryFromDBExtended mais cela n'a pas aidé. Je suis très nouveau à ce sujet, donc j'apprécierais n'importe quel pointeur pour savoir où aller.

Edit: Voici la méthode loadHistoryFromDBExtended:

-(NSMutableDictionary *)loadHistoryFromDBExtended 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    FMDatabase* db = [FMDatabase databaseWithPath:[self getDBPath]]; 

    if (![db open]) 
    { 
     NSLog(@"Could not open db."); 
     [pool release]; 
    } 

    //get users 
    FMResultSet *rs = [db executeQuery:@"SELECT * FROM R order by date desc"]; //query provides result set 

    //create result array 
    NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init]; 

    while ([rs next]) 
    {   
     NSMutableArray *usersDictArray = [NSMutableArray array]; 

     //look up names for id's 
     [usersDictArray addObject:[rs stringForColumn:@"rNames"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"dName"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"date"]]; 
     [myDictionary setObject:usersDictArray forKey:[rs stringForColumn:@"rID"]]; 

     [usersDictArray release]; 
    } 

    //return usersArray; 
    return myDictionary; 

    [myDictionary release]; 

    [pool drain]; 
} 
+1

Est-ce que 'loadHistoryFromDBExtended' renvoie un objet appartenant à l'appelant? Quelle est la déclaration de 'ridesDict'? Est-ce une propriété? Si oui, s'agit-il d'une propriété 'retain' ou' copy'? Utilisez-vous des accesseurs synthétisés pour la propriété ou avez-vous implémenté des accesseurs personnalisés? –

+0

loadHistoryFromDBExtended renvoie myDictionary déclaré dans cette méthode. ridesDict est déclaré dans l'interface et avec @property (non atomic, retain) NSMutableDictionary * ridesDict; en .h puis @synthesize ridesDict; dans le .m –

Répondre

2

La mise en œuvre de cette méthode pose de nombreux problèmes. Dans la vérification pour savoir si le db peut être ouvert ou non, vous libérez le pool autorelease, mais continuez sur le reste du code.Je suppose que vous voudrez probablement retourner nil à ce moment-là. Dans la section [rs next], vous créez un NSMutableArray avec +array, ce qui crée un objet autoreleased. En tant que tel, vous ne devriez pas appeler [usersDictArray release], car cela serait trop relâcher. (Dans chaque boucle, les instances usersDictArray autoréglées «temporaires» seront stockées dans le pool de libération automatique pool Lorsque vous appelez [pool drain], le pool autorelease enverra à toutes ces instances temporaires un message). Vers la fin, vous avez return myDictionary;, ce qui fait que les 2 lignes suivantes ne seront jamais atteintes. Par conséquent, le pool d'autorelease que vous avez créé ne sera jamais publié (sauté).

Ceci est probablement comment je mettre en œuvre:

-(NSMutableDictionary *)loadHistoryFromDBExtended { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    FMDatabase* db = [FMDatabase databaseWithPath:[self getDBPath]]; 

    if (![db open]) 
    { 
     NSLog(@"Could not open db."); 
     [pool release]; 
     return nil; // I'm assuming you should return nil here 
    } 

    //get users; query provides result set 
    FMResultSet *rs = [db executeQuery:@"SELECT * FROM R order by date desc"]; 

    //create result array 
    NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init]; 

    while ([rs next]) 
    {   
     NSMutableArray *usersDictArray = [NSMutableArray array]; 
     //look up names for id's 
     [usersDictArray addObject:[rs stringForColumn:@"rNames"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"dName"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"date"]]; 
     [myDictionary setObject:usersDictArray forKey:[rs stringForColumn:@"rID"]]; 
     // [usersDictArray release]; 
    } 
    [pool drain]; 
    return [myDictionary autorelease]; 
} 

(Notez que la façon dont je mis en œuvre cela suppose que le raisonnement derrière la création d'un pool autorelease local est pour la performance, et qu'il ya un NSAutoreleasePool global en place absorber l'objet auto-libéré final [myDictionary autorelease]).

+0

Comme mentionné dans la réponse de Lou Franco cela résout en effet le problème ainsi que les fuites sur lesquelles je travaillais ensuite. Je vous remercie. –

4

J'ai écrit ce blog pour aider à comprendre et déboguer EXC_BAD_ACCESS

http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html

Afin de facilité

  1. Run a Construire et analyser - obtenez-vous une construction propre ? Regardez ce qu'il dit, mais vous pouvez ignorer les problèmes de fuite pour l'instant - rechercher des problèmes d'envoi de messages aux objets libérés

  2. Exécuter avec NSZombiesEnabled - cela ne libère jamais les objets, puis se plaindre si un message est envoyé à Un objet avec retainCount de 0.

  3. Activez Guard Malloc, puis utilisez les commandes GDB spéciales pour inspecter l'intégrité du tas. Le problème est que vous devez passer à travers et faites ceci avant de vous planter pour trouver le vrai problème. Il pourrait planter ailleurs plus près de votre problème si

+0

je n'étais pas au courant de construire et d'analyser. Très utile, merci. Si vous voyez mon commentaire original, j'ai ajouté la méthode loadHistoryFromDBExtended et j'ai libéré le tableau que j'utilisais pour construire le dictionnaire sur chaque boucle. Je pense que j'étais sous l'impression que je devais le libérer pour effacer le tableau avant de le réutiliser. J'ai encore des fuites mais ça marche maintenant et je peux aller de l'avant. Merci encore. –

1

Essayez d'appeler:

[self.ridesDict retain]; 

avant d'utiliser le dictionnaire (peut-être à init classe). Ne pas oublier d'appeler:

[self.ridesDict release]; 
self.ridesDict = nil; 

à dealloc.

Vérifiez également si vous déclarez correctement la propriété dans l'en-tête. Il doit être:

@property (nonatomic, retain) NSMutableArray *ridesDict; 

Et ajouter @synthesize ridesDict; à votre implémentation de la classe.

+0

Vous devez savoir comment @property a été déclaré savoir si cela est juste. Si c'était avec 'retain', par exemple, vous ne devriez pas faire cela. L'affectation de propriété est automatiquement conservée, et l'affectation à nil libère l'ancien objet. –

+0

Mais "oublier d'appeler retenez" c'est la raison la plus fréquente de faute de segmentation (aka EXC_BAD_ACCESS). Un accord avec vous que cela peut être parce que vous déclarez @property incorrectement. J'oublie que c'est de la classe variable, je pensais (je ne sais pas pourquoi) que c'est du var local. Mais si c'est la classe var, je vous recommande d'ajouter retain dans les paramètres @property – HiTECNOLOGYs

Questions connexes