STARTボタンを押すとタイマーを再セットする
START
ボタンを押すとタイマーが開始するところまで実装ができましたが、実はSTART
ボタンを押した後に再度START
ボタンを押すと残り時間のカウントダウンの数字が速いペースで減っていくようになってしまいます。
これは二重にタイマーが実行されていることが原因で発生しています。なので、タイマーが開始した後にSTART
ボタンを押した場合に再度タイマーが180
から再セットされるように関数startTimer
のコードを変更します。
func startTimer() { // ここを追加↓ timer?.invalidate() remainingTime = 180 // timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in remainingTime -= 1 if remainingTime == 0 { timer?.invalidate() remainingTime = 180 } }) }
タイマーが0になった時の処理と同様に、タイマーを無効化して180
の値を再セットしています。これでタイマーが開始した後に、START
ボタンを押しても再度180
からカウントダウンできるようになりました。
繰り返し使用している処理を関数にする
関数の説明でプログラム内で繰り返し使える処理をひとまとまりにできるとお伝えしました。この関数startTimer
の中を見てみると重複したコードが確認できます。
func startTimer() { // 同じ処理 timer?.invalidate() remainingTime = 180 // timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in remainingTime -= 1 if remainingTime == 0 { // 同じ処理 timer?.invalidate() remainingTime = 180 // } }) }
この繰り返し使用しているコードを切り出した関数resetTimer
を作成します。また、繰り返し同じコードを書いていた箇所をこの関数に置き換えます。
func startTimer() { // ここを追加↓ resetTimer() timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in remainingTime -= 1 if remainingTime == 0 { // ここを追加↓ resetTimer() } }) } // ここを追加↓ func resetTimer() { timer?.invalidate() remainingTime = 180 }
コードは変わりましたが、アプリの動きに変化はないため、START
ボタンを何度押しても残り時間が再セットされることを確認できます。
残り時間を分かりやすい形式に変換する
タイマーの機能はできましたが、アプリ上に表示されている180.000000
という残り時間をもう少し分かりやすい形式に変換していきます。
Swiftには分かりやすい形式に変換してくれるフォーマッターが用意されています。今回はその中から時間量を変換してくれるDateComponentsFormatter
を使用します。まずは次のようにDateComponentsFormatter
を追加してください。
struct CupRamenTimerView: View { @State private var timer: Timer? @State private var remainingTime: Double = 180 // ここを追加↓ let dateFormatter: DateComponentsFormatter = { let dateFormatter = DateComponentsFormatter() dateFormatter.unitsStyle = .short dateFormatter.allowedUnits = [.minute, .second] return dateFormatter }()
まずは今回使用した定数の定義方法を説明します。
let 定数名: 型 = { //生成時に実行する処理 }()
これは、定数を初期化する際に特定の処理を実行するための方法です。初期化時に一度だけ{}
内の処理を実行し、その結果を定数として保持することができます。
定数dateFormatter
の初期化時に実行している処理は次の通りです。
-
DateComponentsFormatter
を生成する -
unitsStyle
で変換する時間量の表示形式を短い形式になるように設定する -
allowedUnits
で表示する単位を分と秒のみが表示されるように設定する
これでフォーマッターの用意はできました。次にアプリ上に表示する文字をこのdataFormatter
を使用して次のように変換します。
var body: some View { ZStack { Color.black .ignoresSafeArea() VStack(spacing: 24) { Text("3分間カップラーメンタイマー") .font(.title3) .bold() .foregroundStyle(.white) // ここを変更↓ Text("\(dateFormatter.string(from: remainingTime) ?? "180")") .font(.system(size: 60)) .fontWeight(.black) .foregroundStyle(.yellow) Button("START") { startTimer() } .font(.largeTitle) } } }
これでプレビューには3min
と残り時間が表示されるようになりました。

変更したコードの詳細を説明すると、Text
の値として、dataFormatter
に残り時間の値を渡して、フォーマットされた文字列を取得しています。ただ、関数dateFormatter.string(from:)
の戻り値がString?
でOptional
になっているため、そのままではText
に反映することができません。??
の記号を用いることで、値が空の場合に任意の値を設定することができます。
以上でカップラーメンタイマーの完成です。
まとめと次回
今回はアプリを作る過程で、ZStack
を使って背景色をつける方法やif文や関数、Timer
を使用する方法を学びました。
今回は、3分間のみしか計測できないため、5分間を必要とするカップラーメンには対応していません。ぜひ、5分間のカップラーメンタイマー作成にもチャレンジしてみてください!
もし、アプリのデザインについてもっと学びたいと感じはじめた方がいましたら、Apple Human Interface GuidelineでAppleのガイドラインを確認することをお勧めします。
次回はアプリ「福笑いゲーム」を作ります。お楽しみに!
