我有以下代码来创建NSTimer
,每次触发时都应更新标签:
.h文件
@interface Game : UIViewController
{
NSTimer *updateTimer;
UILabel *testLabel;
int i;
}
-(void)GameUpdate;
@end
.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
当我运行它时,顶部会出现一个标签,显示“0”但不会改变。它让我相信我错过了NSTimer
如何设置的内容。我错过了什么?
我使用断点和(如您所见)记录以查看方法是否实际运行,而不是其他一些错误。
答案 0 :(得分:14)
我遇到了类似的问题,它有一个与运行循环相关的不同根本原因。值得注意的是,当您使用代码安排Timer时:
updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
计时器将通过当前主题的runLoop进行安排。在你的情况下,因为你在viewDidLoad中进行了这个调用,它是主线程,所以你很高兴。
但是,如果您使用主线程以外的线程安排计时器,它将在该线程的runLoop上进行调度,而不是主线程。哪个没问题,但是在辅助线程上,你负责创建和启动初始运行循环,所以如果你还没有这样做 - 你的回调永远不会被调用。
解决方案是为你的辅助线程启动runLoop,或者将你的计时器启动分配给主线程。
发送:
dispatch_async(dispatch_get_main_queue(), ^{
updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
});
启动runloop:
使用您选择的API创建线程后,调用CFRunLoopGetCurrent()为该线程分配初始运行循环。将来对CFRunLoopGetCurrent的任何调用都将返回相同的运行循环。
CFRunLoopGetCurrent();
updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
答案 1 :(得分:7)
你的回调必须有这个签名:
-(void)GameUpdate:(NSTimer *)timer
这在文档中明确说明。设置计时器时@selector()引用应为@selector(GameUpdate:)
(注意尾随:
)。
试试。
答案 2 :(得分:1)
万一有人偶然发现这一点,我想指出这一点:
[[NSString alloc] initWithFormat:@"Frame: %d", i];
需要内存管理。
安全地替换为:
[NSString stringWithFormat:@"Frame: %d", i];
效果相同但不需要内存管理。
P.S。在撰写本文时,我无法对原帖发表评论,因此我将其添加为答案。
编辑:正如adam waite所指出的那样,这与ARC的广泛使用不再相关。
答案 3 :(得分:0)
我与 NSTimer 有一点不同的问题 - 在UITableView滚动期间忽略了预定的方法调用。 计时器已从主线程启动。明确地向主运行循环添加计时器解决了问题。
String res = "";
for(int i = 0; i < dup; i++) {
res = res + ".";
}
return res;
此处找到解决方案https://stackoverflow.com/a/2716605/1994889
UPD :[[NSRunLoop mainRunLoop] addTimer:playbackTimer forMode:NSRunLoopCommonModes];
更适合更新用户界面。
根据官方文档,CADisplayLink是:
表示绑定到显示vsync的计时器的类。
可以轻松实现,如:
CADisplayLink
并删除
playbackTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateUI)];
[playbackTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];