Диагностика ошибки автоматического выпуска (EXC_BAD_ACCESS) - PullRequest
2 голосов
/ 01 октября 2011

Я играл с основными данными и начал писать несколько методов для запроса различных диапазонов дат данных.Моя базовая модель данных очень проста (сущность с именем Smoke с одним полем - отметка времени (типа date).

Когда я выполняю свой код, возвращается правильное количество, но я получаю ошибку автоматического выпуска - я использовал NSZombiesчтобы отследить его до метода ниже:

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

Итак, я понял - я выпускаю объекты NSDate beginDate и endDate слишком много раз - но почему это происходит? Я думал, что это правило, когда вы создаете экземплярс помощью alloc вы используете release? Я не выпускаю их явно где-то еще в коде, поэтому должно быть что-то происходящее за кулисами. Если бы кто-то мог указать мне правильное направление, это было бы здорово!

Вот другие вовлеченные методы, так как проблема должна быть где-то в них. Я предполагаю, что это связано с тем, как я передаю указатели на даты вокруг?

Первоначальный вызов, вызываемый в представленииКонтроллер

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

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

Этот метод называется началом вопроса, который, в свою очередь, вызывает:

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

Спасибо.s!

Редактировать - исключить связанный метод:

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

1 Ответ

3 голосов
/ 01 октября 2011

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 и endDate - выходные параметры.Они не принадлежат вызывающей стороне, следовательно, они должны не быть освобожденными.

Затем в:

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

происходит следующее:

  1. Вы создаете новый объект NSDate с помощью +alloc, следовательно, вы являетесь его владельцем.beginDate указывает на этот новый объект;

  2. Вы создаете новый NSDate объект с помощью +alloc, следовательно, вы являетесь его владельцем.endDate указывает на этот новый объект;

  3. Вы отправляете -rangeUnit:containingDate:startsAt:andEndsAt:, передавая адреса beginDate и endDate в качестве аргументов.По возвращении эти две переменные указывают на то, что было помещено в них методом.Вы не владеете соответствующими объектами (см. Выше), и вы пропустили два NSDate объекта, которые вы создали в шагах 1 и 2.

  4. Выотправьте -release на beginDate и endDate.Вы не являетесь их владельцем, поэтому не должны их выпускать.

В итоге:

  • Вы не должны создавать новые объектыдля beginDate и endDate, поскольку они возвращаются -rangeUnit… Это вызывает утечки памяти;

  • Вы не должны выпускать beginDate и endDate, потому что выне владейте объектами, возвращаемыми -rangeUnit… Это вызывает перевыпуски.

Следующий код должен исправить ваши утечки и перевыпуски:

- (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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...