Iphone n导致泄漏的计时器
我已经读了很多关于NSTimer的书,但我肯定对它们做了一些非常错误的事情,因为实际上所有的泄漏都出现在泄漏仪器中。“负责框架”列显示-[NSCFTimer或+[NSTimer(NSTimer) 下面是我如何在主菜单中设置NSTimer的。我将其缩短,以显示计时器是如何设置的 .h- .m- (在initWithFrame中) 离开视图时,它会终止计时器:Iphone n导致泄漏的计时器,iphone,xcode,ipad,memory-leaks,nstimer,Iphone,Xcode,Ipad,Memory Leaks,Nstimer,我已经读了很多关于NSTimer的书,但我肯定对它们做了一些非常错误的事情,因为实际上所有的泄漏都出现在泄漏仪器中。“负责框架”列显示-[NSCFTimer或+[NSTimer(NSTimer) 下面是我如何在主菜单中设置NSTimer的。我将其缩短,以显示计时器是如何设置的 .h- .m- (在initWithFrame中) 离开视图时,它会终止计时器: -(void) kill_timers{ [timer_porthole invalidate]; timer_port
-(void) kill_timers{
[timer_porthole invalidate];
timer_porthole=nil;
}
当然,Dealoc:
- (void)dealloc {
[timer_porthole invalidate];
[timer_porthole release];
timer_porthole = nil;
[super dealloc];
}
你错过了
[timer\u porthole release];
调用你的kill\u timers
方法。如果你在调用dealoc
方法之前调用kill\u timers
,你将timer\u porthole
设置为nil,但你没有释放它。你错过了[timer\u porthole release]
调用kill\u timers
方法。如果在调用dealloc
方法之前调用kill\u timers
,则将timer\u porthole
设置为nil,但您没有释放它。不要在NSTimer上调用retain
我知道这听起来有悖常理,但当您创建实例时,它会自动注册到当前(probaby main)线程运行循环(nsrunlop)
计时器与run一起工作
循环。要有效地使用计时器,您需要
应该知道如何运行循环
操作请参见nsrunlop和Threading
编程指南。特别注意
运行循环保留其计时器,因此
您可以在完成后释放计时器
将其添加到跑步循环中。
一旦在运行循环中进行了调度,则
计时器按指定的间隔触发
直到它失效为止
非重复计时器使其自身失效
在它开火之后,但是,
对于重复计时器,您必须
自行使计时器对象无效
通过调用其invalidate方法。
调用此方法会请求
从电流表中移除计时器
运行循环;因此,您应该
始终从调用invalidate方法
计时器所在的线程
已安装。使计时器无效
立即禁用它,使其不会
更长的时间会影响运行循环
循环然后移除并释放
计时器,或者在
invalidate方法返回或在某些
稍后。一旦无效,计时器
对象不能重复使用。
所以你的实例化变成
timer_porthole = [NSTimer scheduledTimerWithTimeInterval:.05
target:self
selector:@selector(onTimer_porthole:)
userInfo:nil
repeats:YES];
现在您不再持有对实例的引用,您将不希望在dealloc方法中使用release调用。不要在NSTimer上调用retain
我知道这听起来有悖常理,但当您创建实例时,它会自动注册到当前(probaby main)线程运行循环(nsrunlop)
计时器与run一起工作
循环。要有效地使用计时器,您需要
应该知道如何运行循环
操作请参见nsrunlop和Threading
编程指南。特别注意
运行循环保留其计时器,因此
您可以在完成后释放计时器
将其添加到跑步循环中。
一旦在运行循环中进行了调度,则
计时器按指定的间隔触发
直到它失效为止
非重复计时器使其自身失效
在它开火之后,但是,
对于重复计时器,您必须
自行使计时器对象无效
通过调用其invalidate方法。
调用此方法会请求
从电流表中移除计时器
运行循环;因此,您应该
始终从调用invalidate方法
计时器所在的线程
已安装。使计时器无效
立即禁用它,使其不会
更长的时间会影响运行循环
循环然后移除并释放
计时器,或者在
invalidate方法返回或在某些
稍后。一旦无效,计时器
对象不能重复使用。
所以你的实例化变成
timer_porthole = [NSTimer scheduledTimerWithTimeInterval:.05
target:self
selector:@selector(onTimer_porthole:)
userInfo:nil
repeats:YES];
现在,您不再持有对实例的引用,您将不希望在dealloc方法中使用release调用。我看到您已经接受了一个答案,但这里有两件事需要纠正:
不需要保留计划的计时器,但它不会造成任何伤害(只要在不再需要时释放它)。计时器/目标关系的“问题”部分是
计时器保留其目标。您已决定将该目标设置为self
这意味着-保留或不保留-只要计时器有效,计时器将使对象保持活动状态
考虑到这一点,让我们从下到上重新审视您的代码:
- (void)dealloc {
[timer_porthole invalidate]; // 1
[timer_porthole release];
timer_porthole = nil; // 2
[super dealloc];
}
1毫无意义:
如果timer\u porthole
仍然是一个有效的计时器(即在runloop上调度),它将保留您的对象,因此首先不会调用此方法
2这里也没有任何意义:
这是dealloc
!当[super dealloc]
返回时,您的实例在堆上占用的内存将被释放。当然,您可以在释放前将堆中的部分清空。但是为什么要麻烦呢
还有
-(void) kill_timers{
[timer_porthole invalidate];
timer_porthole=nil; // 3
}
3鉴于您的初始值设定项(以及其他人指出的),您正在泄漏您的计时器;在这一行之前应该有一个[timer\u porthole release]
附言:
如果你仔细想想,你会发现保留计时器(至少是暂时的)会产生一个保留周期。在这种情况下,这恰好是一个非问题,一旦计时器无效就会得到解决…我看到你已经接受了答案,但这里有两件事我想纠正:
不需要保留计划的计时器,但它不会造成任何伤害(只要在不再需要时释放它)。计时器/目标关系的“问题”部分是
计时器保留其目标。您已决定将该目标设置为<
-(void) kill_timers{
[timer_porthole invalidate];
timer_porthole=nil; // 3
}