ストップウォッチを作ってみた！！

時間を測るアプリを作りたくて、
まずはシンプルなストップウォッチを作ることにしました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">100で1秒になるの知らなかった🥲<br>文字幅が数字ごとに違うって知らなかった🥺<br>コンマ秒を何秒にする計算式が難しかった🦊<br>地味にprintって便利🦊✨<br><br>後悔はしない😌笑 <a href="https://t.co/VDZ6fzPMoZ">pic.twitter.com/VDZ6fzPMoZ</a></p>&mdash; やんも🌈iOSエンジニアになる (@Beer7769) <a href="https://twitter.com/Beer7769/status/1361974118841688064?ref_src=twsrc%5Etfw">February 17, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

![スクリーンショット 2021-02-17 19.05.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737820/a57a474c-c788-9449-8702-fe03a3a2aa40.png)

![スクリーンショット 2021-02-17 19.05.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737820/f4a6735b-7337-c556-410b-fd5a5fefefc6.png)


##参考にしたサイト
ストップウォッチが作りたくて日本語で検索しても、古いものしか出てこなかったので英語で検索したら比較的最近アップされたと思われる動画を見つけることが出来ました。

__▼今回参考にした動画__
[Simple Timer App Swift Xcode Tutorial - Stopwatch (Count up Timer)](https://youtu.be/3TbdoVhgQmE)
__▼サンプルコードのリンク__
[Timer App Example Source Code](https://github.com/codeWithCal/TimerAppSwiftXcode)

__上記以外で参考にしたサイト__
[Swift ストップウォッチ](https://iscene.jimdofree.com/2015/07/10/swift-ストップウォッチ/)
[0.1は浮動小数点数で正確に表せないのに、printしたときに0.1と表示されるのはなぜか](https://qiita.com/yucatio/items/c03def631bc5eaaa9887)
[【swift5】ストップウォッチタイマーの作り方](https://qiita.com/sventouz/items/91faaa4ccdf02a5788bd)
[Apple公式リファレンス　scheduledTimer](https://developer.apple.com/documentation/foundation/timer/2091889-scheduledtimer)
[Apple公式リファレンス Timer](https://developer.apple.com/documentation/foundation/timer)

##開発環境
Swift5
Xcode12.4

#コードの中身の説明
コード全体は、[Timer App Example Source Code](https://github.com/codeWithCal/TimerAppSwiftXcode)を参考にして、自分なりにアレンジした箇所だけ記載していきます。

##ストップウォッチで表示される文字について
シュミレーターを動かしてみて気づいたのですが、
秒が増えるごとにブルブルするというか、震えたようになりました。
それは、数字によって文字幅が違うので、
表示するごとにサイズが変わり、震えたように見える、でした。
以下のリンクを参考にコードを追記しました。
[iOSで等幅フォントを指定する](https://qiita.com/Tsuyoshi84/items/59b30b2b0a4cd49d816b)

```swift
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        startStopButton.setTitleColor(UIColor.green, for: .normal)
        timerLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 60, weight: .medium)
        print("viewDidLoad")
    }
```

[プロポーショナルフォント](https://ja.wikipedia.org/wiki/プロポーショナルフォント)と言って、文字毎に文字幅が異なるフォントのことをいうそうです。
ああ、確かに一文字POPをパワポで作るときに
スライドごとに微調整しないとなんか変な感じになるのは、
プロポーショナルフォントだから、だったんだと思いました。

```swift
        print("viewDidLoad")
```
これは必要ないですが、viewDidLoadが
問題なく動いてくれてるか確認するために書きました。

##初心者だからわからないエラーの文言
![2021-02-17 16.09のイメージ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737820/bb71e9c0-229a-62dc-2545-ec14338981ee.jpeg)
このエラーに1週間くらい悩まされました（笑
エラーが出てるけど、何が原因でシュミレーターが落ちてしまうのかが
まーーーーったくわかりません。

しかし、よーく見てみると赤いところに
__[StopwatchByYoutube.ViewController start:]:unrecognized selector sent to instance__
って言ってる。
何かが、うまく紐付けれてないっぽい。
さらに、startって書いてる。
「スタートボタン」周辺でなにか起こってると予測し、
調べた結果、
![スクリーンショット 2021-02-17 17.04.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737820/433f0722-0b39-d9fd-afa6-478fbb60dd72.png)
インスペクターコネクションのところの、
touch Up Insideのところが、2つあった！！
上図は、直したあとの画像なのですが。
多分、よくある消し忘れです。
ここが原因でエラーが出てたようです。
なんじゃぁ〜♪

##スタートボタンを押した時
```swift
        @IBAction func startStopTapped(_ sender: Any) {
        print("pressButton")
        if(timerCounting) {
            timerCounting = false
            timer.invalidate()
            startStopButton.setTitle("START", for: .normal)
            startStopButton.setTitleColor(UIColor.green, for: .normal)
            print("false")
        } else {
            timerCounting = true
            startStopButton.setTitle("STOP", for: .normal)
            startStopButton.setTitleColor(UIColor.red, for: .normal)
            timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerCounter), userInfo: nil, repeats: true)
            print("true")
        }
    }
```

printのコードは、なくて大丈夫なやつで、
ちゃんと動作してるか確認するために書いてあります。

@スタートボタンが押されたら以下のことをやる。
もし、timerCounting(さっくり言えばストップウォッチのこと）が
　__false(ストップウォッチが動かしてない）場合__
　・タイマーはinvalidate(＝無効化する)
　・スタートストップボタンはSTARTと表示する
　・スタートストップボタンのフォントカラーはグリーンで、ノーマルタイプで表示する
　__true(ストップウォッチが動かしてる）場合__
　・スタートストップボタンはSTOPと表示する
　・スタートストップボタンのフォントカラーは赤で、ノーマルタイプで表示する
　・タイマーを発動。0.01秒ごとに、違うところに書いたtimerCounterを、繰り返し(repeats)実行する。

##時間の計算方法について
動画のサンプルコードは1秒ごとに増えていくストップウォッチでしたが、
私が作りたかったのは、0,01秒からカウントするヤツ。
サンプルコードでは、

```swift
func secondsToHoursMinutesSeconds(seconds: Int) -> (Int, Int, Int)
	{

return ((seconds / 3600), ((seconds % 3600) / 60),((seconds % 3600) % 60))
	}
```
サンプルの方は1秒ごとに1を足していって秒をカウントしていくのですが、
私の場合は0.01秒からカウントしたいのでこのコードだと、
0.6秒で1秒になってしまいました。

```swift
return ((seconds / 3600), ((seconds % 3600) / 60), seconds)
	}
```
書き換えてみたけど、このコードだと、
0.1秒が60で繰り上がらなくなる,0.6秒で1秒になるは変わらない。

ここで気づいたのが、これ多分一般常識なんだろうけど、
0.01秒が100になったときに1秒になる。
1秒が60秒になったときに、1分になる。
いや、当たり前なんですけど、あんまり意識したことなかったので、
そもそも、この計算式だと違うくなっちゃうよね、ということで、

```swift
return ((seconds / 6000), ((seconds / 100) % 60), (seconds % 100))
```

これが正解でした。
secondsが、0.01秒ごとに1増えていく。
__(seconds % 100)__
％で割ったあまりを表示させるってなってるけど、
直訳はそんな感じですが、ニュアンスでいうと、
どこまで表示させたいか、で考えればわかりやすいかなぁと思います。
今回は0.01秒が100になったときに1秒になるので、
100になったら0からカウントし直したい。
なので、「100で割って、そのあまりを表示させる」

__((seconds / 100) % 60)__
0.01秒が100になったら1秒になって、
60秒で1分になるから、
0.01が6000になったときに1分になるようにしたいから、
6000を100で割って、何秒なのかを計算して、それを60であまりを出すことで、
60秒になったら0からまたカウントするようになる。

この計算式考えるのに、結構頭使いました笑


##%02dで、「00」を表示させる

```swift
func makeTimeString(hours: Int, minutes: Int, seconds: Int) -> String {
        var timeString = ""
        timeString += String(format: "%02d", hours)
        timeString += " : "
        timeString += String(format: "%02d", minutes)
        timeString += " . "
        timeString += String(format: "%02d", seconds)
        return timeString
    }
```
"%02d"ってすると0のときに00で表示させることができる。
あと、 timeString += " . "　も、変更しました。
サンプルでは：になってたのですが、
AppleWatchのストップウォッチを見てみると、
コンマ秒は" . "になってたので、変更しました。

#勉強になったこと
__英語で検索する__
やったほうがいいのはわかっていたけど、
やはり英語で検索すると全然情報量が違いました。
Youtubeで学習する際も、英語で検索したほうがいっぱい出てくる。
確かに何かしゃべってるかわからないけど、
十分理解することができる。

最初は、違うサイトを見ながらストップウォッチを作成したけど、
バージョンが古かったりで、完成に辿り着けなかった。
初心者の私には、アレンジとかまだ、わからないので、
英語で検索して最新の情報をキャッチしたほうが早いと思いました。

__1秒の詳細__
0.01秒が100になったときに1秒になるのが衝撃的。
普通にみんな知ってることなのかな？？
60秒で1分なのに、0.01秒はなんで100なんだ？
ただ、そこまで掘り下げる必要もないので流します。

__プロポーショナルフォント__
ただ単に数字を表示させるだけだと思っていたけど、
実際に作ってみたら「なるほど」そういうことも考えないといけないのね、
ということがわかった。

__エラーと向き合う__
以前、「絶対コードはあってるのにエラーがでる」という発想は捨てることにしました。
なぜなら「どこかが絶対違うからエラーがでる」から。
そこは良かったのだけど、向き合うってことが出来てなかったなぁと。
エラーコードもよく見れば、場所まで教えてくれてるし、
ヒントらしき単語はちゃんと読めば書いてある。
次からは、ちゃんとエラーとじっくり向き合おうと思いました。



#まとめ
初めて「自分の作りたいものを自分で作った！」って感じ、最高に気持ちいい。