好像我一直在问同样的问题,与记忆有关。我当前的代码完全符合我的意图,但我无法理解为什么我在仪器中显示泄漏。
-(NSDate *)startTimeAndDate {
NSDate *dateToReturn = nil;
if (startTimeAndDate != nil) {
dateToReturn = [startTimeAndDate retain];
} else { //is currently nil, this will be the initial setting
//return default time if we have a working date
if (finishTimeAndDate != nil) {
dateToReturn = [[self dateFromDate:finishTimeAndDate withNewTime:defaultStartTime]retain];
} else {
//return the default time with today's date if we have nothing set as yet
dateToReturn = [[self dateFromDate:[NSDate date] withNewTime:defaultStartTime] retain];
}
//save the initial setting
self.initialStartDateAndTime = [[dateToReturn copy] autorelease];
}
[startTimeAndDate release];
startTimeAndDate = dateToReturn;
return startTimeAndDate;
}
-(void)setStartTimeAndDate:(NSDate *)inStartTimeAndDate {
BOOL initialAssignment = NO;
if (startTimeAndDate == nil) {
initialAssignment = YES;
}
if (startTimeAndDate != inStartTimeAndDate) { //skip everything if passed object is same as current
//check that the start time is prior to finish only if finish time has been entered
NSDate *dateToSetStartTo = nil;
if (finishTimeAndDate != nil) {
if ([inStartTimeAndDate earlierDate:finishTimeAndDate] == inStartTimeAndDate) {
// use the new time, it is earlier than current finish time
dateToSetStartTo = [inStartTimeAndDate retain];
} else { //start time is not earlier then finish time
// the received entry is invalid, set start time to 1 default interval from finish
dateToSetStartTo = [[finishTimeAndDate dateByAddingTimeInterval:-self.defaultTimeInterval] retain];
}
} else { //finish time is nil
// use the new time without testing, nothing else is set
dateToSetStartTo = [inStartTimeAndDate retain];
}
[startTimeAndDate release];
startTimeAndDate = dateToSetStartTo;
}
if (initialAssignment) {
self.initialStartDateAndTime = [[self.startTimeAndDate copy] autorelease];
}
}
据我所知,我正在使用release
或autorelease
来平衡所有保留。泄漏似乎仅在第一次通过时引起。我有一个视图控制器,它创建我的模型(其中这个代码所在)并设置一个开始日期,此时没有其他任何事情。如果我在那时关闭那个视图控制器,仪器显示我将日期对象作为泄漏。
我放置一个NSLog
来显示dealloc
的保留计数,当然,在我的最终版本被调用之前,它保留了2的计数,当它应该被保留为1时保留计数销毁。无论我是在初始化后立即关闭还是设置并获得一百次,它始终是相同的。在我retainCount
release
dealloc
的最终通话之前,startTimeAndDate
已经过了2。
我整个周末都在看这个,但无法弄清楚我哪里出错了。
为了澄清,最初的调用是设置startTimeAndDate
属性。此时,如果不是对象,则所有其他字段都为零或0。 {{1}}对象似乎是泄漏对象。
答案 0 :(得分:4)
首先,您能描述一下您尝试使用此代码解决的问题吗?我问,因为它看起来非常复杂,我最初的想法是简化不仅会澄清你在做什么,而且也可能解决你的泄漏问题。
其次,(我可能有这个错误),你只需要保留/释放对象,如果你希望这些对象存在于方法的范围之外,或者你希望它们可能被某些代码发布克制你的方法。基于此,您似乎在代码中过度保留和释放。我想你可以删除很多。
我可能错了,但看起来你确实会泄漏。我这么认为的原因是 - 在你的第一次传递中,你在dateToReturn
中保留了一些本地变量的数据。然后你做
self.initialStartDateAndTime = [[dateToReturn copy] autorelease];
但这不会发布dateToReturn
。相反,它正在发布dateToReturn
的副本。 dateToReturn
仍然保留。假设您打算自动发布副本,因为initialStartDateAndTime
设置为retain,我认为您应该这样做:
self.initialStartDateAndTime = [[dateToReturn copy] autorelease];
[dateToReturn release];
当然,如果您删除额外的保留/释放,那么这会再次变得更简单。
我建议的最后一件事是围绕命名。像这样的代码的问题是你有许多方法和变量,都有非常相似的名称。这可能使其难以遵循并导致错误。所以问问自己是否真的需要这么多变量。并且您可以通过更改一些名称来使您的代码更易读。
答案 1 :(得分:2)
另一件事是,在程序中的其他地方执行的代码会保留日期。因此引发泄漏。例如,如果inStartTimeAndDate
的保留计数为1,但调用setter的代码未释放,那么最终可能会使用startTimeAndDate
并保留2。
话虽如此,这是我重写吸气剂以试图澄清最新情况:
-(NSDate *)startTimeAndDate {
// If we have it, bail out fast.
if (startTimeAndDate == nil) {
return startTimeAndDate;
}
// Is currently nil, this will be the initial setting
NSDate *dateToReturn = nil;
//return default time if we have a working date
if (finishTimeAndDate != nil) {
dateToReturn = [self dateFromDate:finishTimeAndDate withNewTime:defaultStartTime];
} else {
//return the default time with today's date if we have nothing set as yet
dateToReturn = [self dateFromDate:[NSDate date] withNewTime:defaultStartTime];
}
//save the initial setting
self.initialStartDateAndTime = [[dateToReturn copy] autorelease];
startTimeAndDate = [dateToReturn retain];
return startTimeAndDate;
}
重写的主要原因是,如果有startTimeAndDate
,那么代码就是这样做了:
dateToReturn = [startTimeAndDate retain];
...
[startTimeAndDate release];
startTimeAndDate = dateToReturn;
这似乎有点无意义,因为它有效地进行保留,释放和自我分配。它会起作用,但是如果我们把它遗漏的话就会有更少的机会。