タコさんブログ

プログラミングメモと小言

Swift NSTimer の基本的な使い方

環境

  • Xcode 7.3 (7.1)
  • Swift 2.2 (2.1)

タイマーの生成とRun Loopに登録を同時に行う場合

// targetObjectのObjective-Cで利用できるfunc update(timer: NSTimer)を1秒間隔で呼び出す
// (または、Objective-Cクラスを継承したSwiftクラス)
NSTimer.scheduledTimerWithTimeInterval(1.0, target: targetObject, selector: #selector(TargetObject.update(_:)), userInfo: nil, repeats: true)
/* Swift 2.1の場合
NSTimer.scheduledTimerWithTimeInterval(1.0, target: targetObject, selector: "update:", userInfo: nil, repeats: true)
*/

タイマーの生成とRun Loopに登録を別で行う場合

// targetObjectのObjective-Cで利用できるfunc update(timer: NSTimer)を1秒間隔で呼び出す
// (または、Objective-Cクラスを継承したSwiftクラス)
let timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: targetObject, selector: #selector(TargetObject.update(_:)), userInfo: nil, repeats: true)
/* Swift 2.1の場合
let timer = NSTimer(timeInterval: 1.0, target: targetObject, selector: "update:", userInfo: nil, repeats: true)
*/
// run loopに登録する
// run loopに登録することでタイマー処理が開始される
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)

任意のタイミングでタイマーに登録したターゲットのメソッドを呼ぶ

timer.fire()

※ リピートしないタイマーの場合は、自動的に無効化(invalidate)される

タイマーの停止

timer.invalidate()

タイマーの参照について

タイマーはRun Loopにより強参照(strong reference)で保持されるので、Run Loopに追加されたタイマー(Scheduled Timer)を強参照で保持しておく必要はない。この時、タイマーを停止する必要があるなどの理由により保持する場合は、弱参照(weak reference)で良い。Run Loopに追加していないタイマー(Unscheduled Timer)の場合は、解放されないように強参照で保持する必要がある。

Scheduled Timerの例

class TimerExample {
    weak var timer: NSTimer?  // 弱参照

    // タイマー開始
    func startTimer() {
        timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(TimerExample.update(_:)), userInfo: nil, repeats: true)
        /*   Swift 2.1の場合
        timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "update:", userInfo: nil, repeats: true)
        */
    }

    func stopTimer() {
        timer?.invalidate()
    }

    @objc func update(timer: NSTimer) {
        print("update")
    }
}

Unscheduled Timerの例

class TimerExample {
    var timer: NSTimer?  // 強参照

    // タイマー生成
    func createTimer() {
        timer = NSTimer(timeInterval: 1.0, target: self, selector: #selector(TimerExample.update(_:)), userInfo: nil, repeats: true)
        /* Swift 2.1の場合
        timer = NSTimer(timeInterval: 1.0, target: self, selector: "update:", userInfo: nil, repeats: true)
        */
    }

    // Run Loopに登録
    func startTimer() {
        if let timer = timer {
            NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
        }
    }

    func stopTimer() {
        timer?.invalidate()
    }

    @objc func update(timer: NSTimer) {
        print("update")
    }
}

Timer Coalescing (Tolerance)

タイマーのtoleranceを設定することにより、システム側がtoleranceの範囲内でターゲットのメソッドをまとめて呼びだすように調整してくれる(下の図のような感じ)。これにより省エネになる。
リピートタイマーの場合、toleranceの範囲は少なくとも呼びだし間隔の10%を目安にするのが良い。

f:id:tiny_wing:20151120133342p:plain

toleranceの設定  

timer.tolerance = 1.0

iOS 10 で追加された Timer API (Swift 3.0)

タイマーのコールバックがクロージャで記述できるようになった。

public init(timeInterval interval: TimeInterval, repeats: Bool, block: @escaping (Timer) -> Swift.Void)

public convenience init(fire date: Date, interval: TimeInterval, repeats: Bool, block: @escaping (Timer) -> Swift.Void)

class func scheduledTimer(withTimeInterval interval: TimeInterval, repeats: Bool, block: @escaping (Timer) -> Swift.Void) -> Timer

Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in
  print(timer.fireDate)
}

参考URL