NSTimer的动作方法没有被调用

rde*_*fin 0 cocoa-touch objective-c nstimer ios

我有以下代码来创建一个NSTimer应该在每次触发时更新标签的代码:

.h文件

@interface Game : UIViewController
{
    NSTimer *updateTimer;

    UILabel *testLabel;
    int i;
}
-(void)GameUpdate;

@end
Run Code Online (Sandbox Code Playgroud)

.m文件

@implementation Game

-(void)GameUpdate
{
    i++;
    NSString *textToDisplay = [[NSString alloc] initWithFormat:@"Frame: %d", i];
    [testLabel setText:textToDisplay];
    NSLog(@"Game Updated");
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
    updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
}

//other methods (viewDidUnload, init method, etc.)

@end
Run Code Online (Sandbox Code Playgroud)

当我运行它时,顶部会出现一个标签,显示"0"但不会改变.它让我相信我错过了如何NSTimer设置.我错过了什么?

我使用断点和(如您所见)记录以查看方法是否实际运行,而不是其他一些错误.

Sco*_*len 14

我遇到了类似的问题,它有一个与运行循环相关的不同根本原因.值得注意的是,当您使用代码安排Timer时:

updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
Run Code Online (Sandbox Code Playgroud)

计时器将使用当前线程的runLoop进行调度.在你的情况下,因为你在viewDidLoad中进行了这个调用,它是主线程,所以你很高兴.

但是,如果使用主线程以外的线程安排计时器,它将在该线程的runLoop上进行调度,而不是主线程.这很好,但是在辅助线程上,你负责创建和启动初始运行循环,所以如果你还没有这样做 - 你的回调永远不会被调用.

解决方案是为您的辅助线程启动runLoop,或者将您的计时器启动分配给主线程.

派遣:

dispatch_async(dispatch_get_main_queue(), ^{
    updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
});
Run Code Online (Sandbox Code Playgroud)

要启动runloop:

使用您选择的API创建线程后,调用CFRunLoopGetCurrent()为该线程分配初始运行循环.将来对CFRunLoopGetCurrent的任何调用都将返回相同的运行循环.

CFRunLoopGetCurrent();
updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
Run Code Online (Sandbox Code Playgroud)


Mar*_*off 7

你的回调必须有这个签名:

-(void)GameUpdate:(NSTimer *)timer
Run Code Online (Sandbox Code Playgroud)

这在文档中明确说明.设置计时器时的@selector()引用应该是@selector(GameUpdate:)(注意尾随:).

试试吧.