我已经阅读了很多关于NSTimers的内容,但我必须对它们做一些非常错误的事情,因为它实际上是Leaks仪器中出现的所有泄漏。 “责任框架”栏目显示 - [NSCFTimer或+ [NSTimer(NSTimer)。
所以这就是我在主菜单中设置NSTimer的方法。我将其简化为显示定时器的设置方式。
.h -
@interface MainMenu : UIView {
NSTimer *timer_porthole;
}
@end
@interface MainMenu ()
-(void) onTimer_porthole:(NSTimer*)timer;
@end
.m -
(在initWithFrame中)
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
timer_porthole = [[NSTimer scheduledTimerWithTimeInterval:.05
target:self
selector:@selector(onTimer_porthole:)
userInfo:nil
repeats:YES] retain];
}
return self;
}
离开视图时会杀死计时器:
-(void) kill_timers{
[timer_porthole invalidate];
timer_porthole=nil;
}
当然,dealloc:
- (void)dealloc {
[timer_porthole invalidate];
[timer_porthole release];
timer_porthole = nil;
[super dealloc];
}
答案 0 :(得分:4)
请勿在您的NSTimer上调用retain!
我知道这听起来有点反直觉但是当你创建实例时,它会自动注册到当前(probaby main)线程运行循环(NSRunLoop)。这就是苹果公司在这个问题上所说的话......
计时器与run一起工作 循环。要有效地使用计时器,你 应该知道如何运行循环 操作 - 参见NSRunLoop和线程 编程指南。 特别注意 运行循环保留其计时器,所以 你有可以释放计时器 将其添加到运行循环中。
一旦在运行循环上安排,就可以了 计时器以指定的间隔触发 直到它失效。一个 非重复计时器使自身无效 火灾发生后立即发生。然而, 对于重复计时器,你必须 自己使计时器对象无效 通过调用其invalidate方法。 调用此方法请求 从当前删除计时器 运行循环;结果,你应该 总是从中调用invalidate方法 与计时器相同的线程 安装。 计时器无效 立即禁用它,以便它没有 更长时间会影响运行循环。运行 然后循环删除并释放 计时器,就在之前 invalidate方法返回或在某些方面返回 以后点。一旦失效,计时器 对象无法重复使用。
所以你的实例化变成......
timer_porthole = [NSTimer scheduledTimerWithTimeInterval:.05
target:self
selector:@selector(onTimer_porthole:)
userInfo:nil
repeats:YES];
现在您不再持有对实例的引用,您不希望在dealloc方法中调用release。
答案 1 :(得分:3)
我见过你已经接受了答案,但我想在这里纠正两件事:
self
这意味着 - 保留或不保留 - 只要计时器有效,计时器就会使你的对象保持活着状态。考虑到这一点,让我们从下到上重新审视您的代码:
- (void)dealloc {
[timer_porthole invalidate]; // 1
[timer_porthole release];
timer_porthole = nil; // 2
[super dealloc];
}
1 毫无意义:
如果timer_porthole
仍然是一个有效的计时器(即在runloop上安排)它将保留你的对象,所以这个方法不会被调用...
2 这里没有意义:
这是dealloc
!当[super dealloc]
返回时,将释放实例在堆上占用的内存。当然,你可以在释放之前将你的部分内容弄清楚。但为什么要这么麻烦?
然后有
-(void) kill_timers{
[timer_porthole invalidate];
timer_porthole=nil; // 3
}
3 鉴于您的初始化程序(正如其他人指出的那样),您在此处泄露计时器;在此行之前应该有一个[timer_porthole release]
。
PS:
如果你认为一切都结束了,你会发现保留计时器(至少是暂时的)会创建一个保留周期。在这种特殊情况下恰好是一个非问题,一旦计时器失效就解决了......
答案 2 :(得分:0)
您在[timer_porthole release];
方法中错过了kill_timers
来电。如果您在调用kill_timers
方法之前致电dealloc
,则将timer_porthole
设置为nil,但您没有将其释放。