Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c NSTimer';未调用的操作方法_Objective C_Ios_Cocoa Touch_Nstimer - Fatal编程技术网

Objective c NSTimer';未调用的操作方法

Objective c NSTimer';未调用的操作方法,objective-c,ios,cocoa-touch,nstimer,Objective C,Ios,Cocoa Touch,Nstimer,我有以下代码来创建一个NSTimer,它应该在每次触发时更新标签: .h文件 @interface Game : UIViewController { NSTimer *updateTimer; UILabel *testLabel; int i; } -(void)GameUpdate; @end .m文件 @implementation Game -(void)GameUpdate { i++; NSString *textToDisplay

我有以下代码来创建一个
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
时遗漏了一些东西。我错过了什么


我使用断点和(如您所见)日志来查看该方法是否正在实际运行,而不是其他错误。

您的回调必须具有以下签名:

-(void)GameUpdate:(NSTimer *)timer
这在文档中是明确的。设置计时器时的@selector()引用应该是
@selector(GameUpdate:)
(注意后面的


试试看。

为了防止有人无意中发现这一点,我想指出:

[[NSString alloc] initWithFormat:@"Frame: %d", i];
需要内存管理

安全替换为:

[NSString stringWithFormat:@"Frame: %d", i];
同样的效果,但不需要内存管理

另外,在写这篇文章的时候,我无法对原文发表评论,所以我补充了这一点作为回答


编辑:正如下面指出的,这与ARC的广泛使用不再相关。

我也遇到过类似的问题,它有不同的根本原因,与运行循环有关。值得注意的是,当您使用代码计划计时器时:

updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01428 target:self selector:@selector(GameUpdate) userInfo:nil repeats:YES];
计时器将使用当前线程的runLoop进行调度。在您的情况下,因为您在viewDidLoad中进行了此调用,所以它是主线程,所以您可以继续

但是,如果您使用主线程以外的线程调度计时器,那么它将在该线程的运行循环上调度,而不是在主线程上调度。这很好,但是在辅助线程上,您负责创建和启动初始运行循环,因此如果您没有这样做,您的回调将永远不会被调用

解决方案是启动辅助线程的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];

对于NSTimer,我遇到了一个稍微不同的问题—在UITableView滚动期间忽略了预定的方法调用。 计时器已从主线程启动。将计时器显式添加到主运行循环解决了该问题

[[NSRunLoop mainRunLoop] addTimer:playbackTimer forMode:NSRunLoopCommonModes];
这里找到了解决方案

UPD
CADisplayLink
更适合更新用户界面。 根据官方文件,CADisplayLink是:

类,表示绑定到显示vsync的计时器

并且可以很容易地实现,如:

  playbackTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateUI)];
 [playbackTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
然后像

if (playbackTimer) {
    [playbackTimer removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    playbackTimer = nil;
}

那么,该方法实际运行吗?你看到“游戏更新”不止一次吗?谢谢你的回答。我也有同样的问题。谢谢你,伙计,在header的文档中一个字也没有!苹果真是太遗憾了。你没有在那里真正解释“需要内存管理”
initWithFormat
返回保留的实例,而
stringWithFormat
返回自动删除的实例。大多数在方法名(
arrayWithArray
etc)中描述返回值的方法在整个过程中都遵循此约定。这与ARC无关了!