在按下主页按钮时暂停 NSTimer,并在应用程序处于前台后再次启动它们

Pause NSTimer on home-button-press and start them again once the app is in foreground

我一直在寻找一种解决方案,以便在用户 "tabs down" 游戏时暂停我的 SpriteKit 游戏。到目前为止,我找到了一个使用 SKAction 而不是 NSTimer 的解决方案,只要操作之间的时间保持不变,它就可以工作。但是,我的NSTimer的速度发生了变化。所以我需要找到另一个解决方案。

我有一堆 NSTimer 位于 GameScene -> didMoveToView

NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: Selector("SpawnBullets"), userInfo: nil, repeats: true)

NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("SpawnMeteors"), userInfo: nil, repeats: true)

NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("onTimer:"), userInfo: nil, repeats: true)

现在,我该如何在应用程序进入后台时简单地暂停它们?

编辑:添加了我的时间间隔增加速度功能

func onTimer(timer: NSTimer) {
    var goodTimes = time / 20

    if (goodTimes > 1.8){
        goodTimes = 1.8
    }

    timer.fireDate = timer.fireDate.dateByAddingTimeInterval(timeInterval - goodTimes)

    self.runAction(SKAction.sequence([SKAction.runBlock(SpawnRocks), SKAction.waitForDuration(goodTimes / 2), SKAction.runBlock(SpawnPowerUp)]))
}

NSTimer 的暂停不是 objective-c 或 swift 的原生功能。为了解决这个问题,您需要创建一个扩展,我恰好创建了这个扩展并将与您分享。这将适用于 OS X 和 iOS

import Foundation
import ObjectiveC

#if os(iOS)
    import UIKit
#else
    import AppKit
#endif


private var pauseStartKey:UInt8 = 0;
private var previousFireDateKey:UInt8 = 0;

extension NSTimer
{
    private var pauseStart: NSDate!{
        get{
            return objc_getAssociatedObject(self, &pauseStartKey) as? NSDate;

        }
        set(newValue)
        {
            objc_setAssociatedObject(self, &pauseStartKey,newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN);
        }
    }

    private var previousFireDate: NSDate!{
        get{
            return objc_getAssociatedObject(self, &previousFireDateKey) as? NSDate;

        }
        set(newValue)
        {
            objc_setAssociatedObject(self, &previousFireDateKey,newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN);
        }
    }


    func pause()
    {
        pauseStart = NSDate();
        previousFireDate = self.fireDate;
        self.fireDate = NSDate.distantFuture() ;
    }

    func resume()
    {
        if(pauseStart != nil)
        {
            let pauseTime = -1 * pauseStart.timeIntervalSinceNow;
            let date = NSDate(timeInterval:pauseTime, sinceDate:previousFireDate );
            self.fireDate = date;
        }

    }
}

然后当你需要使用它时,只需调用 timer.pause()timer.resume() 你当然必须在你的游戏场景对象中跟踪你的计时器才能做到这一点,所以确保 timer 是整个 class 可访问的变量,在制作计时器时,您需要 timer = NSTimer.schedule...

在你的开头 class:

var spawnBulletsTimer : NSTimer?;
var spawnMeteorsTimer : NSTimer?;
var onTimer: NSTimer?;

创建计时器时:

spawnBulletsTimer = NSTimer.scheduledTimerWithTimeInterval(0.2, target:     self, selector: Selector("SpawnBullets"), userInfo: nil, repeats: true)

spawnMeteorsTimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("SpawnMeteors"), userInfo: nil, repeats: true)

onTimer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("onTimer:"), userInfo: nil, repeats: true)

然后需要暂停的时候:

onTimer?.pause() 
spawnBulletsTimer?.pause()
spawnMeteorTimer?.pause()

那么当你需要恢复时:

onTimer?.resume() 
spawnBulletsTimer?.resume()
spawnMeteorTimer?.resume()