2009-12-17 5 views
0

Hey. J'ai travaillé sur une application Twitter et j'ai été bloqué sur une erreur EXC_ BAD_ ACCESS pendant un certain temps. Je sais que EXC_ BAD_ ACCESS est un problème de mémoire mais je ne peux pas identifier où le problème est. Voici mon exemple de code:Pourquoi je reçois un EXC_BAD_ACCES

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    NSString *path = @"/Volumes/Schools/BHS/Student/740827/Documents/Forrest McIntyre CS193P/Presence2"; 
    NSArray *propList = [NSArray arrayWithContentsOfFile:[NSBundle pathForResource:@"TwitterUsers" ofType:@"plist" inDirectory:path]]; 

    people = [[NSMutableArray alloc]init]; 

    for (NSString *name in propList) { 
    Person *p = [[Person alloc] initWithUserName: name]; 
    [people addObject: p]; 
    [p release]; 
    } 
    // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 
    // self.navigationItem.rightBarButtonItem = self.editButtonItem; 
} 

L'exception est levée sur la dernière accolade après le commentaire. Je crois qu'il est vraiment jeté dans la boucle for quelque part, mais apparaît juste à la sortie.

Voici le fichier de mise en œuvre Personne:

@implementation Person 
@synthesize image; 
@synthesize username; 
@synthesize displayName; 
@synthesize statusArray; 

-(id)initWithUserName:(NSString *)userName { 
if(self = [super init]) 
{ 
    self.username = userName; 
    NSDictionary *info = [TwitterHelper fetchInfoForUsername:userName]; 
    self.displayName = [info objectForKey:@"name"]; 
    NSLog([NSString stringWithFormat:@"%@",[info objectForKey:@"profile_image_url"]]); 
    NSString *imageURL2 = [NSString stringWithFormat:@"%@",[info objectForKey:@"profile_image_url"]]; 
    self.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: imageURL2]]]; 
    [info release]; 
    self.statusArray = [TwitterHelper fetchTimelineForUsername:userName]; 
} 
return self; 
} 
@end 

Merci pour toute aide

EDIT: Voici le fichier d'en-tête pour PersonListViewController (la classe qui contient le viewDidLoad). Ceci est juste pour vous montrer d'où les gens viennent.

@interface PersonListViewController : UITableViewController { 
    NSMutableArray *people; 
} 

@end 
+0

Comment avez-vous déclaré la propriété username de Person, est-elle conservée ou copiée? –

Répondre

9

puisque vous ne conserviez propList ou path vous ne devriez pas les libérer.

Vous devez cependant libérer people

Pour un aperçu de la gestion de la mémoire, consultez le Memory Management Programming Guide

Pour des solutions rapides, essayez l'analyseur statique.

+0

Relâcher 'people' devrait probablement être avant qu'il ne lui attribue une nouvelle valeur. Pour moi, cela ressemble à une variable globale. –

+0

bon point.Il devrait être libéré (ou autoreleased) quelque part si – cobbal

+0

Les gens ne peuvent pas être libérés. Il est utilisé dans cellForRowAtIndexPath. C'est aussi une variable globale. Il est publié dans la méthode Dealloc. – Forrest

1

Débogage EXC_BAD_ACCESS est difficile à déboguer. Cela se produit lorsqu'un message est envoyé à un objet déjà publié. Vous devez trouver ce qui cause cette erreur générique en activant la variable d'environnement NSZombiEnabled afin que l'environnement Objective-C puisse 'suivre' un objet désalloué. En utilisant cela, lorsque vous obtenez l'erreur, vous pouvez déterminer où l'erreur s'est produite en regardant la pile des appels. Vous ne saurez pas où il est libéré, mais au moins, cela vous rapprochera.

Je ne l'ai pas configuré ici, mais vous pouvez également passer un pointeur vers l'erreur qui provoquera l'objet à ne pas persister en tant que zombie/mannequin.

En fin de ligne, vous devez vous assurer que les variables que vous souhaitez libérer, que vous les conserviez si nécessaire.

Ce Q technique & A par Apple donne des conseils sur Finding bugs with EXC_BAD_ACCESS.

3

Je pense que le problème est ici:

[propList release]; 

Depuis que vous avez créé à l'aide PropList arrayWithContentsOfFile vous n'avez pas besoin de le libérer - il sortira automatiquement. L'autorelease est en fait ce qui cause l'erreur, car il essaie de libérer quelque chose que vous avez déjà publié manuellement. ETA: comme mentionné ci-dessus, vous n'avez pas besoin de sortir path.

+0

La plus grande courbe d'apprentissage pour moi était d'apprendre (et j'apprends toujours) quand je devrais sortir ou non. Si vous libérez un objet de l'API, vous devriez obtenir EXC_BAD_CRAP mais parfois la documentation/en-tête ne le montre pas - Vous devez avoir confiance que tout le monde respecte les conventions de nommage qui, personnellement, me semblent nul. – Chris

+0

Et ajouter est la plus grande faille dans ce qui est un joli environnement de programmation. – Chris

+0

@Chris: Je suis entièrement d'accord. Les règles de gestion de la mémoire merveilleusement cohérentes et simples de Cocoa sont l'une de ses plus grandes forces. À court de collecte des ordures, je pense que le paradigme traditionnel de gestion de mémoire de cacao est le plus beau que j'ai vu. – Chuck

1

D'une part, aucun de ceux-ci sont nécessaires dans votre exemple:

[path release]; 
[propList release]; 

parce que:

path est une chaîne littérale (existera toujours)

propList est autoreleased

0

http://www.cocoadev.com/index.pl?NSZombieEnabled peut être utile pour localiser les bogues EXC_BAD_ACCESS. Au lieu de désallouer des objets quand ils sont release d il les met dans un état de zombie qui soulève une exception quand ils sont ensuite accédés. Assurez-vous de ne jamais publier de code avec cet ensemble de drapeaux, car cela entraînera des fuites de mémoire.

0

qu'est-ce que c'est self.editButtonItem? Je ne le vois pas dans votre fichier .h

+0

Ceci est commenté. C'est un code qui est automatiquement placé là si vous souhaitez implémenter et modifier le bouton sur la barre de navigation – Forrest

0

Un couple de choses.

  • En initWithUserName: vous obtenez d'informations à partir d'une méthode qui ne contient pas alloc/copier/créer. De plus, vous ne le retenez pas explicitement. Pourtant, vous le libérez. Ceci est problématique en supposant que fetchInfoForUsername: libère son résultat comme attendu selon les règles de gestion de la mémoire Cocoa. L'utilisation d'accesseurs de propriété dans les initialiseurs est considérée comme une mauvaise forme, car elle peut provoquer l'envoi de notifications KVO pour une instance semi-cuite.

1

Pour les erreurs EXC_BAD_ACCESS, vous essayez généralement d'envoyer un message à un objet libéré. Le meilleur façon de suivre ces vers le bas est l'utilisation NSZombieEnabled.

Cela fonctionne en ne libérant jamais réellement un objet, mais en l'enveloppant comme un "zombie" et en plaçant un drapeau à l'intérieur disant qu'il aurait normalement été libéré. De cette façon, si vous essayez d'y accéder à nouveau, vous savez toujours ce que c'était avant de faire l'erreur, et avec ce petit peu d'information, vous pouvez généralement revenir en arrière pour voir quel était le problème.

Il aide en particulier dans les threads d'arrière-plan lorsque le débogueur manque parfois d'informations utiles.

TRÈS IMPORTANT DE NOTER Cependant, c'est que vous devez vous assurer à 100% que c'est seulement dans votre code de débogage et pas votre code de distribution. Parce que rien n'est jamais publié, votre application va fuir et fuir et fuir. Pour me rappeler de ce faire, je mets ce journal dans mon appdelegate:

if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled")) 
    NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!"); 

Si vous avez besoin d'aide pour trouver la ligne exacte, compilons et-Debug (CMD -Y) au lieu d'un Build- et-Exécuter (CMD-R). Lorsque l'application tombe en panne, le débogueur vous montrera exactement quelle ligne et en combinaison avec NSZombieEnabled, vous devriez être capable de savoir exactement pourquoi.

Questions connexes