我一直在研究核心数据,并开始编写一些方法来查询不同日期范围的数据。我的核心数据模型非常简单(名为 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];
}
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:containDate: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;
}
关于iphone - 诊断自动释放错误(EXC_BAD_ACCESS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7617923/