2011-10-01 2 views
2

J'ai joué avec les données de base et j'ai commencé à écrire des méthodes pour interroger différentes plages de dates. Mon modèle de données de base est très simple (Entité nommée Fumée avec un champ - horodatage (de type date)Diagnostic d'une erreur de libération automatique (EXC_BAD_ACCESS)

Lorsque j'exécute mon code, le nombre correct est renvoyé, mais je reçois une erreur de libération automatique - j'ai utilisé NSZombies pour suivre à la méthode ci-dessous:

- (NSUInteger)retrieveSmokesForUnit:(NSCalendarUnit)unit 
{ 
    NSDate *beginDate = [[NSDate alloc] init]; 
    NSDate *endDate = [[NSDate alloc] init]; 
    [self rangeForUnit:unit containingDate:[NSDate date] startsAt:&beginDate andEndsAt:&endDate]; 
    NSInteger count = [self numberOfSmokes:beginDate toDate:endDate]; 

    [beginDate release]; 
    [endDate release]; 

    return count; 
} 

donc je reçois le concept - je publierai les objets NSDate beginDate et endDate trop de fois - mais pourquoi est-ce que cela se produise je pensais que la règle était quand vous instanciez avec alloc, vous? Je ne les libère pas explicitement ailleurs dans le code, donc il doit y avoir quelque chose qui se passe dans les coulisses Si quelqu'un pouvait me pointer dans la bonne direction, ce serait génial!

Voici les autres méthodes impliquées, puisque le problème doit être quelque part dans ceux-ci. Je suppose que cela a à voir avec la façon dont je passe des indications sur les dates?

L'appel initial, appelé dans le contrôleur de vue

- (IBAction)cigButtonPressed 
{ 
    NSUInteger smokes = [[DataManager sharedDataManager] retrieveSmokesForUnit:NSWeekCalendarUnit]; 

    NSLog(@"Count test = %i", smokes); 
} 

Ce Calles la méthode a affiché un début de la question, qui appelle à son tour:

- (NSUInteger)numberOfSmokes:(NSDate *)beginDate toDate:(NSDate *)endDate { 

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Smoke" inManagedObjectContext:self.managedObjectContext]; 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 

    //Create predicate 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(timeStamp >= %@) AND (timeStamp < %@)", beginDate, endDate]; 

    //Setup request 
    [request setEntity:entity]; 
    [request setPredicate:predicate]; 

    NSError *error; 
    NSUInteger smokes = [self.managedObjectContext countForFetchRequest:request error:&error]; 
    NSLog(@"Number of smokes retrieved: %d", smokes); 
    [request release]; 
    return smokes;  
} 

Merci!

Edition - gauche d'un procédé connexe:

- (void)rangeForUnit:(NSCalendarUnit)unit containingDate:(NSDate *)currentDate startsAt:(NSDate **)startDate andEndsAt:(NSDate **)endDate { 

    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 

    [calendar rangeOfUnit:unit startDate:&*startDate interval:0 forDate:currentDate]; 
    *endDate = [calendar dateByAddingComponents:[self offsetComponentOfUnit:unit] toDate:*startDate options:0]; 
    [calendar release]; 
} 
+0

Quand j'ai eu un problème de autorelease (qui produit frustrante peu d'informations de débogage) J'ai réussi à le réduire en créant et drainer les pools d'autorelease autour des blocs de code (en prenant soin de conserver toutes les valeurs qui doivent persister à travers le 'drain'). Vous finirez par arriver dans une petite zone où votre piscine provoque le problème. –

+0

J'ai été en mesure de le réduire aux lignes [beginDate release] et [endDate release] dans retrieveSmokesForUnit ... si je les supprime, il fonctionne très bien sans crash ... – Jim

+0

Ah, avec le code ajouté, le problème est assez évident. Vous créez les objets de date (conservés), puis les superposez avec les versions auto-libérées dans rangeForUnit, puis relâchez les versions auto-libérées (en laissant les objets de date d'origine qui fuient, BTW). –

Répondre

3

In:

- (void)rangeForUnit:(NSCalendarUnit)unit containingDate:(NSDate *)currentDate startsAt:(NSDate **)startDate andEndsAt:(NSDate **)endDate { 

    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 

    [calendar rangeOfUnit:unit startDate:&*startDate interval:0 forDate:currentDate]; 
    *endDate = [calendar dateByAddingComponents:[self offsetComponentOfUnit:unit] toDate:*startDate options:0]; 
    [calendar release]; 
} 

startDate et endDate sont des paramètres de sortie. Ils sont et non appartenant à l'appelant, par conséquent, ils devraient pas être libérés.

Puis, en:

- (NSUInteger)retrieveSmokesForUnit:(NSCalendarUnit)unit 
{ 
    NSDate *beginDate = [[NSDate alloc] init]; 
    NSDate *endDate = [[NSDate alloc] init]; 
    [self rangeForUnit:unit containingDate:[NSDate date] startsAt:&beginDate andEndsAt:&endDate]; 
    NSInteger count = [self numberOfSmokes:beginDate toDate:endDate]; 

    [beginDate release]; 
    [endDate release]; 

    return count; 
} 

suivantes se produit:

  1. Vous créez un nouvel objet NSDate via +alloc, d'où vous en êtes propriétaire. beginDate points à ce nouvel objet; Vous créez un nouvel objet NSDate via +alloc, par conséquent vous le possédez. endDate points à ce nouvel objet;

  2. Vous envoyez -rangeUnit:containingDate:startsAt:andEndsAt: en transmettant l'adresse beginDate et endDate comme arguments. Au retour, ces deux variables pointent vers ce qui leur a été placé par la méthode. Vous ne pas possèdent les objets correspondants (voir ci-dessus), et vous avez eu une fuite les deux objets NSDate créés dans les étapes 1 et 2.

  3. Vous envoyez -release à la fois beginDate et endDate. Vous ne les possédez pas, par conséquent vous ne devriez pas les libérer.

En résumé:

  • Vous ne devriez pas être en train de créer de nouveaux objets pour beginDate et endDate car ils sont renvoyés par -rangeUnit… Cela provoque des fuites de mémoire;

  • Vous ne devez pas libérer beginDate et endDate car vous ne possédez pas les objets retournés par -rangeUnit… Cela provoque des surcharges.

Le code suivant devrait fixer vos fuites et overreleases:

- (NSUInteger)retrieveSmokesForUnit:(NSCalendarUnit)unit 
{ 
    NSDate *beginDate; 
    NSDate *endDate; 
    [self rangeForUnit:unit containingDate:[NSDate date] startsAt:&beginDate andEndsAt:&endDate]; 
    NSInteger count = [self numberOfSmokes:beginDate toDate:endDate]; 

    return count; 
} 
+0

+1 pour une excellente explication! – Rog

+0

Votre excellente explication m'a rapproché de la compréhension de la gestion de la mémoire Obj-C. Merci beaucoup!! – Jim