iphone - 诊断自动释放错误(EXC_BAD_ACCESS)

标签 iphone objective-c memory-management

我一直在研究核心数据,并开始编写一些方法来查询不同日期范围的数据。我的核心数据模型非常简单(名为 Smoke 的实体,具有一个字段 - 时间戳(日期类型)。

当我执行代码时,会返回正确的计数,但出现自动释放错误 - 我使用 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?我没有在代码中的其他任何地方明确地释放它们,所以幕后肯定有一些事情发生。如果有人能指出我正确的方向,那就太好了!

以下是涉及的其他方法,因为问题肯定出在这些方法中的某个地方。我认为这与我如何传递指向日期的指针有关?

初始调用,在 View Controller 中调用

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

谢谢!

编辑 - 遗漏了相关方法:

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

最佳答案

在:

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

startDateendDate 是输出参数。它们属于调用者,因此它们不应该被释放。

然后,在:

- (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. 您通过+alloc创建一个新的NSDate对象,因此您拥有它。 beginDate 指向这个新对象;

  2. 您通过+alloc创建一个新的NSDate对象,因此您拥有它。 endDate 指向这个新对象;

  3. 您发送 -rangeUnit:containDate:startsAt:andEndsAt:,并将 beginDateendDate 的地址作为参数传递。返回时,这两个变量指向该方法放入其中的任何内容。您拥有相应的对象(见上文),并且您泄漏了在步骤 1 和 2 中创建的两个 NSDate 对象。

  4. 您将 -release 发送到 beginDateendDate。您不拥有它们,因此您不应该释放它们。

总结:

  • 您不应该为 beginDateendDate 创建新对象,因为它们是由 -rangeUnit 返回的...导致内存泄漏;

  • 您不应该释放 beginDateendDate,因为您不拥有 -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;
}

关于iphone - 诊断自动释放错误(EXC_BAD_ACCESS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7617923/

相关文章:

ios - UIButton 中的按钮标题意外更改

ios - Objective-C - 分配、复制、保留

c - 从文件中读取并在动态结构上传输

iPhone 应用程序 : Linking to review page

ios - 如何在 iPhone 上获取快门速度、光圈和 ISO 值

iphone - 在 iOS 应用程序的辅助 View 中时无法识别耳机按钮按下

iphone - UILabel 文本错误

iphone - 导航 Controller 应用程序中 2 个 UIViewcontroller 的方向问题

python - 进程重新启动时内存未回收

ios - UIKit-[UIApplication sendAction :to:from:forEvent:] crash