我一直在玩核心数据,并开始编写一些方法来查询不同的数据日期范围。我的核心数据模型非常简单(实体名为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?我不会在代码中的任何其他位置显式释放它们,因此必须在幕后发生一些事情。如果有人能指出我正确的方向,那就太好了!
以下是涉及的其他方法,因为问题必须在这些方面。我假设它与我如何传递指向日期的指针有关?
在视图控制器中调用的初始调用
- (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 :(得分: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];
}
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;
}
发生以下情况:
您通过NSDate
创建了一个新的+alloc
对象,因此您拥有它。 beginDate
指向此新对象;
您通过NSDate
创建了一个新的+alloc
对象,因此您拥有它。 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;
}