こちらはTimerを使って簡単なstopwatchを作ってみました。
Xcode 11.4
Timer
では色々な使用法を想定していますが、scheduledTimerを使うやり方が分かりやすいでしょう。
1 2 3 |
class func scheduledTimer(timeInterval ti: TimeInterval, invocation: NSInvocation, repeats yesOrNo: Bool) -> Timer |
1 2 3 4 5 |
class func scheduledTimer(timeInterval ti: TimeInterval, target aTarget: Any, selector aSelector: Selector, userInfo: Any?, repeats yesOrNo: Bool) -> Timer |
Timerの基本的使い方
スケジューリングしない方法もありますが、今回は2つ目のメソッドを使ってみます。
ViewController.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import UIKit class ViewController: UIViewController { var timer: Timer! override func viewDidLoad() { super.viewDidLoad() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(true) startTimer() } func startTimer() { timer = Timer.scheduledTimer( timeInterval: 0.01, target: self, selector: #selector(self.timerCounter), userInfo: nil, repeats: true) } @objc func timerCounter() { let now = Date() let fomatter = DateFormatter() fomatter.dateFormat = "mm:ss.SSS" print(fomatter.string(from: now)) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(true) timer.invalidate() } } |
いきなりアプリ起動とともにTimerを使う事は無いかもしれませんが、viewDidLoadでは早いこともあるのでviewDidAppearでTimerのスケジュールをして開始した方がいいようです。
fire()は使わなくても起動します(入っていてもエラーにはなりませんが)
Logはこのようになりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
00:23.253 00:23.262 00:23.273 00:23.283 00:23.293 00:23.302 00:23.313 00:23.323 00:23.332 00:23.342 00:23.352 00:23.362 00:23.372 00:23.382 00:23.393 00:23.403 |
0.01sec間隔ですが0.001secのズレがあります。余り厳しくタイムカウントをするとバッテリー消費が激しいでしょうね
Stopwatchサンプルコード
Timerを使ってStopwatchアプリを作ってみます。
インターバルでカウントアップしてそれを元にタイムを表示してもいいのですが、ちょっと厳密にディレーが起きても開始時間からのタイムを取り出すようにしてみました。
ViewController.swif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
import UIKit class ViewController: UIViewController { @IBOutlet var timerMinute: UILabel! @IBOutlet var timerSecond: UILabel! @IBOutlet var timerMSec: UILabel! weak var timer: Timer! var startTime = Date() override func viewDidLoad() { super.viewDidLoad() // 画面背景色を設定してみました self.view.backgroundColor = UIColor(red:0.9,green:1.0,blue:0.9,alpha:1.0) } @IBAction func startTimer(_ sender : Any) { if timer != nil{ // timerが起動中なら一旦破棄する timer.invalidate() } timer = Timer.scheduledTimer( timeInterval: 0.01, target: self, selector: #selector(self.timerCounter), userInfo: nil, repeats: true) startTime = Date() } @IBAction func stopTimer(_ sender : Any) { if timer != nil{ timer.invalidate() timerMinute.text = "00" timerSecond.text = "00" timerMSec.text = "00" } } @objc func timerCounter() { // タイマー開始からのインターバル時間 let currentTime = Date().timeIntervalSince(startTime) // fmod() 余りを計算 let minute = (Int)(fmod((currentTime/60), 60)) // currentTime/60 の余り let second = (Int)(fmod(currentTime, 60)) // floor 切り捨て、小数点以下を取り出して *100 let msec = (Int)((currentTime - floor(currentTime))*100) // %02d: 2桁表示、0で埋める let sMinute = String(format:"%02d", minute) let sSecond = String(format:"%02d", second) let sMsec = String(format:"%02d", msec) timerMinute.text = sMinute timerSecond.text = sSecond timerMSec.text = sMsec } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(true) timer.invalidate() } } |
タイムをformatterで1つのLabelにしようと思ったのですが、Font幅が一定で無いと微妙に表示位置が動きます。冗長的ですがラベルを分けて表示させました。
後はstoryboardでボタンとタイムを表示するラベルを紐付けます。それぞれフォントサイズや背景色を適宜合わせて出来上がりです。
サンプル動画
References:
Timer – Foundation | Apple Developer Documentation
Date – Foundation | Apple Developer Documentation