2011-10-01 105 views
2

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

当我执行我的代码时,正确的计数会返回,但我得到一个autorelease错误 - 我使用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日期和结束日期过很多次 - 但为什么这种情况发生我认为规则是,当你用ALLOC实例,你呢?使用版本?我没有明确地在代码中的任何其他地方发布它们,所以一定会有幕后的事情发生。如果有人可以指引我朝着正确的方向发展,那将是非常好的!

以下是涉及的其他方法,因为问题必须在这些方面。我认为这与我如何传递指向日期的指针有关?

最初的电话,称在视图控制器

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

当我有一个自动的问题(其产生令人沮丧的一点调试信息)我已经成功通过创建缩小它与耗尽代码块周围的自动释放池(注意保留必须保留在“漏极”上的任何值)。你最终会下到一个小地方,在那里你的泳池会引发问题。 –

+0

我可以缩小到retrieveSmokesForUnit中的[beginDate release]和[endDate release]行...如果我删除这些,它运行良好,没有崩溃... – Jim

+0

啊,用添加的代码,问题是漂亮的明显。您创建(保留的)日期对象,然后使用rangeForUnit中的自动发布版本覆盖它们,然后释放自动发布的版本(保留原始日期对象泄漏,顺便说一下)。 –

回答

3

在:

- (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:containingDate:startsAt:andEndsAt:,通过地址beginDateendDate作为参数。返回后,这两个变量指向该方法所放置的任何内容。你做拥有相应的对象(见上文),你已经泄露你发-releasebeginDateendDate您在步骤1中创建两个NSDate对象和2

  4. 。你不拥有它们,因此你不应该释放它们。

总结:

  • 你不应该创建beginDateendDate新的对象,因为他们正在通过-rangeUnit…返回这将导致内存泄漏;

  • 您不应该发布beginDateendDate,因为您不拥有由-rangeUnit…返回的对象,这会导致过度销售。

下面的代码应该解决您的泄漏和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为一个很好的解释! – Rog

+0

您的出色解释让我更进一步了解了Obj-C内存管理。非常感谢你!! – Jim