当应用程序进入后台时停止/启动 NSTimer

Adr*_*n P 1 objective-c nstimer ios sprite-kit skscene

正如标题所暗示的那样,当我的游戏进入后台时,我试图停止我的 NSTimer,并在游戏再次开始时重新启动它。中断显然可能是接听电话等。

我在应用程序委托中使用以下代码在应用程序中断时停止并重新启动场景,但它不会停止计时器。

- (void)applicationWillResignActive:(UIApplication *)application {

    SKView *view = (SKView *)self.window.rootViewController.view;
    view.scene.paused = YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {

    SKView *view = (SKView *)self.window.rootViewController.view;
    view.scene.paused = NO;
}
Run Code Online (Sandbox Code Playgroud)

在我放置计时器的场景中,我将观察者放置在-(id)initWithSize:(CGSize)size方法中。以下是观察员:

[[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(goBackground)
         name:UIApplicationDidEnterBackgroundNotification
         object:nil];

[[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(backBackground)
         name:UIApplicationDidBecomeActiveNotification object:nil];
Run Code Online (Sandbox Code Playgroud)

和选择器方法:

- (void) goBackground {
    [timer invalidate], timer = nil;
}

- (void) backBackground {
    if([timer isValid]) {
        [timer invalidate];
    }
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateCounter:) userInfo:nil repeats:YES];

}
Run Code Online (Sandbox Code Playgroud)

我还试图按如下方式解除分配观察者:

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}
Run Code Online (Sandbox Code Playgroud)

上面的代码被触发了,我在上面的所有方法上都放置了一个 NSLog。但发生的情况是,它适用于场景 1,这是第 1 级的地方,当玩家赢得第 1 级并进入第 2 级,我再次重新创建应用程序中断场景时,它会在游戏开始前几秒钟返回并工作崩溃。

显然我的代码不起作用,我已经尝试了所有我知道如何解决这个问题的方法,但无济于事。我拥有的计时器只是为了显示关卡还剩下多少时间,与输赢情况无关。(这可能是一些可能不需要知道的额外信息)。

无论如何,当我的游戏进入后台时,我可以停止并重新启动我的计时器吗?我真的很感激任何帮助。

我不知道是否需要计时器代码,但如下所示:

- (void) gameTimerLabel {
    gameTimerLabel = [SKLabelNode labelNodeWithFontNamed:@"ArialRoundedMTBold"];
   // gameTimerLabel.text = [NSString stringWithFormat:@"%d", _lives];
    gameTimerLabel.fontSize = 20.0;
    gameTimerLabel.fontColor = [SKColor colorWithRed:135.0/255 green:207.0/255 blue:232.0/255 alpha:0.6];
    gameTimerLabel.position = gameTimerLabel.position = CGPointMake(270, 282);
    [self addChild:gameTimerLabel];
}

- (void)updateCounter:(NSTimer *)theTimer {
    if(secondsLeft > 0 ){
        secondsLeft -- ;
        //hours = secondsLeft / 3600;
        minutes = (secondsLeft % 3600) / 60;
        seconds = (secondsLeft %3600) % 60;
        gameTimerLabel.text = [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];
    }
    else{
        secondsLeft = 70;
    }
}

-(void)countdownTimer{

    secondsLeft = hours = minutes = seconds = 0;
    if([timer isValid]) {
        [timer invalidate];
    }
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateCounter:) userInfo:nil repeats:YES];

}
Run Code Online (Sandbox Code Playgroud)

它基本上只是一个倒数计时器,没什么特别的。

编辑:

Ben-G,是对的。几乎没有办法在后台/前台管理 NSTimer,所以我使用了 SKAction 方法并且确实完成了工作。对于那些有兴趣的人,这里是工作代码:

@implementation MyScene {
SKLabelNode *gameTimerLabel;
int countDownInt;
    int secondsLeft;
}

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
secondsLeft = 70;
[self gameTimerLabel];
}
    return self;
}

- (void) gameTimerLabel {
    gameTimerLabel = [SKLabelNode labelNodeWithFontNamed:@"ArialRoundedMTBold"];
    gameTimerLabel.fontSize = 20.0;
    gameTimerLabel.fontColor = [SKColor colorWithRed:135.0/255 green:207.0/255 blue:232.0/255 alpha:0.6];
    gameTimerLabel.position = gameTimerLabel.position = CGPointMake(270, 282);
    [self addChild:gameTimerLabel];
    countDownInt = secondsLeft;
    SKAction *updateLabel = [SKAction runBlock:^{
        gameTimerLabel.text = [NSString stringWithFormat:@" %02d", countDownInt];
        --countDownInt;
    }];
    SKAction *wait = [SKAction waitForDuration:1.0];
    SKAction *updateLabelAndWait = [SKAction sequence:@[updateLabel, wait]];
    [self runAction:[SKAction repeatAction:updateLabelAndWait count:secondsLeft] completion:^{
        gameTimerLabel.text = @"Time's Up";
    }];
}
Run Code Online (Sandbox Code Playgroud)

就这样。再次感谢 Ben-G 为我指明了正确的方向。

Ben*_*n-G 5

即使它没有完全回答你的问题,我还是会参考这个问题的公认答案:SpriteKit - 创建一个计时器

一般来说,你想避免使用 NSTimer游戏引擎时。您的定时操作不会与游戏循环集成,并且您的计时器不会在游戏暂停时自动停止。

而是与update方法集成或使用SKAction.