Iphone n导致泄漏的计时器

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

我已经读了很多关于NSTimer的书,但我肯定对它们做了一些非常错误的事情,因为实际上所有的泄漏都出现在泄漏仪器中。“负责框架”列显示-[NSCFTimer或+[NSTimer(NSTimer)

下面是我如何在主菜单中设置NSTimer的。我将其缩短,以显示计时器是如何设置的

.h-

.m-

(在initWithFrame中)

离开视图时,它会终止计时器:

-(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
    }