簡體   English   中英

未調用NSTimer的action方法

[英]NSTimer's action method is not being called

我有以下代碼來創建一個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 我錯過了什么?

我使用斷點和(如您所見)日志記錄來查看該方法是否真正在運行,而不是其他一些錯誤。

我遇到了類似的問題,並且它具有與運行循環相關的根本原因。 值得注意的是,當您使用代碼安排計時器時:

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];
});

要啟動運行循環:

使用您選擇的API創建線程后,調用CFRunLoopGetCurrent()為該線程分配初始運行循環。 將來對CFRunLoopGetCurrent的任何調用都將返回相同的運行循環。

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

您的回調必須具有以下簽名:

-(void)GameUpdate:(NSTimer *)timer

這是明確地在文檔中。 和@selector()引用,當你設置定時器應@selector(GameUpdate:) (注意尾隨: )。

試試看

以防萬一有人偶然發現這一點,我想指出一點:

[[NSString alloc] initWithFormat:@"Frame: %d", i];

需要內存管理。

安全地替換為:

[NSString stringWithFormat:@"Frame: %d", i];

具有相同的效果,但不需要內存管理。

PS:在撰寫本文時,我無法對原始帖子發表評論,因此,我將其添加為答案。

編輯:正如亞當·懷特在下面指出的那樣,這與ARC的廣泛使用不再相關。

我在NSTimer中遇到了一些不同的問題-UITableView滾動期間忽略了計划的方法調用。 計時器已從主線程啟動。 將計時器顯式添加到主運行循環可解決此問題。

[[NSRunLoop mainRunLoop] addTimer:playbackTimer forMode:NSRunLoopCommonModes];

在這里找到解決方案https://stackoverflow.com/a/2716605/1994889

UPDCADisplayLink更適合更新UI。 根據官方文檔,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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM