Iphone 诊断自动释放错误(EXC\u错误访问)

Iphone 诊断自动释放错误(EXC\u错误访问),iphone,objective-c,memory-management,Iphone,Objective C,Memory Management,我一直在玩弄核心数据,并开始编写一些方法来查询数据的不同日期范围。我的核心数据模型非常简单(实体名为Smoke,带有一个字段-timestamp(日期类型) 当我执行代码时,会返回正确的计数,但我会得到一个自动释放错误-我使用NSZombies跟踪到以下方法: - (NSUInteger)retrieveSmokesForUnit:(NSCalendarUnit)unit { NSDate *beginDate = [[NSDate alloc] init]; NSDate *e

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

当我执行代码时,会返回正确的计数,但我会得到一个自动释放错误-我使用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?我没有在代码中的任何其他地方显式发布它们,所以一定有一些事情在幕后发生。如果有人能告诉我正确的话t方向,那太好了

这里是涉及的其他方法,因为问题一定在这些方法中的某个地方。我想这与我如何传递指向周围日期的指针有关

初始调用,在视图控制器中调用

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

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;
}
发生以下情况:

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

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

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

  • 您将
    -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;
    }
    

    当我遇到自动释放问题(产生令人沮丧的小调试信息)时,我通过在代码块周围创建和排空自动释放池(注意保留必须在整个
    排空过程中保留的任何值),设法缩小了问题的范围。您最终会进入一个小区域,您的池会引发问题。我能够将其缩小到retrieveSmokesForUnit中的[beginDate release]和[endDate release]行……如果我删除这些行,它运行良好,没有崩溃……啊,添加代码后问题非常明显。您创建了(保留)日期对象,然后在rangeForUnit中用自动删除的版本覆盖它们,然后发布自动删除的版本(顺便说一句,保留原始日期对象泄漏)。是不是&in
    [calendar RangeoUnit:unit startDate:&*startDate
    错误?RangeoUnit不修改startDate.@ott该
    &*
    最终是一个无操作,可以删除。您出色的解释使我更进一步了解Obj-C内存管理。非常感谢!!
    - (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;
    }
    
    - (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;
    }