如何在Objective-C中取消NSTimer的定时任务

5

我在一个应用程序中使用嵌套的NSTimer。 我有两个问题。

  1. 如何在此函数 - (void)updateLeftTime:(NSTimer *)theTimer 中重新初始化计时器
  2. 如何终止以前的定时器,因为 - (void)updateLevel:(NSTimer *)theTimer 也由定时器调用。

- (void)viewDidLoad {
    [super viewDidLoad];

    tmLevel=[NSTimer scheduledTimerWithTimeInterval:20.0f target:self selector:@selector(updateLevel:) userInfo:nil repeats:YES];

    tmLeftTime=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLeftTime:) userInfo:nil repeats:YES];
}

- (void)updateLevel:(NSTimer *)theTimer {
    static int count = 1;
    count += 1;

    lblLevel.text = [NSString stringWithFormat:@"%d", count];

    tfLeftTime.text=[NSString stringWithFormat:@"%d",ANSWER_TIME];

    tmLeftTime=[[NSTimer alloc] init];
    tmLeftTime=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLeftTime:) userInfo:nil repeats:YES];
    [self playMusic];

}
- (void)updateLeftTime:(NSTimer *)theTimer {
    static int timeCounter=1;
    timeCounter+=1;
    tfLeftTime.text=[NSString stringWithFormat:@"%d", (ANSWER_TIME-timeCounter)];
}
4个回答

17
  • 使用[tmLevel invalidate]来取消一个定时器的计划。
  • 别忘了在调度器被取消并释放后,立即将tmLevel=nil设置为nil(以避免在使用变量之前使用定时器)。
  • 不要忘记在失去对tmLevel定时器引用前使其无效,即在给tmLevel变量分配新的NSTimer之前,调用[tmLevel invalidate](否则先前的定时器将继续运行,除了新的定时器之外)。

请注意,在您的代码中,存在无用的内存分配,而且会导致内存泄漏:

tmLeftTime=[[NSTimer alloc] init];
tmLeftTime=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLeftTime:) userInfo:nil repeats:YES];

在这里,您分配了一个NSTimer实例,并将该实例存储在tmLeftTime中...然后立即忘记了创建的此实例,以用另一个使用[NSTimer scheduledTimerWithTimeInterval:...]创建的实例替换它!因此,使用[[NSTimer alloc] init]创建的NSTimer实例丢失了,会导致泄漏(因为它永远不会被释放)。

您的第一行是完全无用的,就像您正在执行以下操作:

int x = 5;
x = 12; // of course the value "5" is lost, replaced by the new value

11

当你想要重置计时器时,添加以下行:

[tmLeftTime invalidate]; 
tmLeftTime = nil;

你也可以使用

if ([tmLeftTime isValid]){
  // the timer is valid and running, how about invalidating it
  [tmLeftTime invalidate]; 
    tmLeftTime = nil;
}

0

使用一个定时器代替三个定时器怎么样?

- (void)viewDidLoad {
    [super viewDidLoad];

    tmLeftTime=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLeftTime:) userInfo:nil repeats:YES];
}

- (void)updateLevel {
    static int count = 1;
    count += 1;

    lblLevel.text = [NSString stringWithFormat:@"%d", count];

    tfLeftTime.text=[NSString stringWithFormat:@"%d",ANSWER_TIME];

    [self playMusic];

}
- (void)updateLeftTime:(NSTimer *)theTimer {
    static int timeCounter=1;
    timeCounter+=1;
    tfLeftTime.text=[NSString stringWithFormat:@"%d", (ANSWER_TIME-timeCounter)];
    if (timeCounter >= ANSWER_TIME) {
        timeCounter = 0;
        [self updateLevel];
    }
}

0
在你的 updateLevel: 方法中使用 invalidate 方法来使计时器失效,并重新安排同一个计时器。
[tmLevel invalidate];
tmLevel = [NSTimer scheduledTimerWithTimeInterval:20.0f target:self selector:@selector(updateLevel:) userInfo:nil repeats:YES];

如果你想调用updateTimeLeft:方法,你不需要再分配另一个计时器,因为你从未释放这些引用,这是一个很大的泄漏。

tmLeftTime = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLeftTime:) userInfo:nil repeats:YES];

在你的 updateTimeLeft: 方法中,只需重新安排计时器的方法并设置一个应该停止的条件。
tmLeftTime = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLeftTime:) userInfo:nil repeats:YES];

哦!我明白了,但实际上我还在中途,所以代码不完整,我必须在完成一个级别后恢复它,而一个级别有20个问题。完成一个级别后,我必须展示广告。因此,我必须重新启动它。非常感谢。 - Shivomkara Chaturvedi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接