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%を目安にするのが良い。
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) }