タイマー機能を作成する
今回、実現したい機能は、3分間をカウントダウンするタイマー機能です。これから、順を追って作成手順を説明していきます。
タイマーを用意する
まずは必要なタイマーと残り時間を保持するための変数を用意します。
struct CupRamenTimerView: View {
// ここを追加↓ タイマー
@State private var timer: Timer?
// ここを追加↓ 残り時間 (3分 = 180秒)
@State private var remainingTime: Double = 180
var body: some View {
ZStack {
Color.black
.ignoresSafeArea()
タイマーのTimerは、指定された時間が経過したタイミングで任意の処理を実行するために使用できます。具体的には、タイマーを設定し、時間が経過すると、指定されたターゲットにメッセージを送信します。そのメッセージの受け取りをトリガーにして処理を実行します。この機能を使うことで、アプリ内で指定した時間間隔後に自動的に処理を実行することができます。
また、Timer?の後ろについている?ですが、これはOptionalの値を示すもので、オプショナルについては後ほど説明します。
残り時間remainingTimeは、カップラーメンタイマーの残り時間を表すための変数です。Double型で定義していて、180は3分(180秒)を意味しています。
値があるかを表す値「Optional」とは?
Optionalとは、値があるか空かを表す値です。この次のコードを例にしますと、Timerという値が空の状態も許容します。また、初期値を渡していないため、初期値は空になります。Swiftでは値が空の状態のことをnilといいます。
@State private var timer: Timer?
今回はTimerで説明しましたが、String?やInt?などの記述ももちろん可能です。
タイマーを開始する関数を作成する
Timerの用意はできましたので、次はタイマーを開始する関数を作成していきます。まだ、関数についての説明ができていないため、ここで少し関数について理解を深めましょう。
関数
関数とは、特定の実行したい処理をひとまとまりにしたものです。関数を使うことで、プログラム内で繰り返し使える処理を定義して、任意のタイミングで実行することが可能です。
定義方法
関数は、次のような形式で定義します。
func 関数名(引数名: 型) -> 戻り値の型 {
// 関数呼び出し時に実行される処理
}
もう少し具体例をみてみましょう。
次の例は合計値を算出する関数です。引数として、leftNumberとrightNumberを受け取れるようにしています。この引数は複数設定することができます。戻り値は、関数実行後に返す値のことを指し、returnキーワードを使用して、戻り値を指定でき、この関数では合計の値を返しています。
func sum(leftNumber: Int, rightNumber: Int) -> Int {
return leftNumber + rightNumber
}
// 使用例
let totalNumber = sum(leftNumber: 1, rightNumber: 2)
また、引数がない場合や戻り値がない場合は次の関数のように省略することもできます。
func printHello() {
print("Hello!")
}
// 使用例
printHello()
関数の定義方法を理解したので実際にタイマーを実行する関数を作成していきましょう。
タイマーを開始する関数
まずは変数bodyの下に関数startTimer()を追加します。
struct CupRamenTimerView: View {
@State private var timer: Timer?
@State private var remainingTime: Double = 180
var body: some View {
// 省略...
}
// ここを追加↓
func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
remainingTime -= 1
})
}
}
このTimer.scheduledTimerは、指定された時間間隔ごとに任意の処理を実行するタイマーを作成できます。それぞれの引数の役割は次のようになっています。
- withTimeInterval:タイマーを起動する時間間隔
- repeats:繰り返しタイマーを起動するか
- block:タイマーが起動された時に行いたい処理を記述する処理ブロック
今回は、1秒間隔で繰り返し、残り秒数を1つマイナスするタイマーを作成して、すでに作成済みの変数Timerに代入しています。
複合代入演算子
タイマーを開始する関数の中で-=という演算子を使用して、残り時間を1つマイナスする処理を書きました。
remainingTime -= 1
上記の処理は下記のコードと行っていることは同じです。
remainingTime = remainingTime - 1
複合代入演算子-=を使用することで処理が簡潔になっています。もちろん+=といった他の算術でも同様の書き方をすることができます。
タイマーの残り時間が0未満にならないようにする
現状のstartTimerの処理では、1秒ごとに残り時間を1マイナスし続けてしまいます。このアプリでは3分間の経過を分かるようにしたいので、0になるとタイマーが止まるようにしたいです。次のようにコードを変更します。
func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
remainingTime -= 1
// ↓ここを追加
if remainingTime == 0 {
timer?.invalidate()
remainingTime = 180
}
})
}
この追加した処理は、残り時間remainingTimeが0になった時にタイマーを無効にして、残り時間の値を180に戻しています。
ここでifという記述をしており、これが制御構文の一つif文になります。
if文
if文は条件が成立しているかどうかで実行する処理を分けることができます。次のような形式で記述します。
if 条件文 {
// 条件成立時に実行する処理
}
この条件文はBool値を返す式である必要があります。
今回のタイマーの実装では、if remainingTime == 0 {と残り時間が0という条件がtrueなら後続の処理を実行するようにしています。
また、条件が成立していない場合でもif文にelseをつけると任意の処理を実行したい処理も行えます。
if 条件文 {
// 条件成立時に実行する処理
} else {
// 条件不成立時に実行する処理
}
タイマーを無効にする
タイマーが0になった時にtimer?.invalidate()という関数を実行していました。これを実行するとTimerを無効にでき、その後は設定している時間がきてもタイマー内の処理は実行されなくなります。
ボタンを押すとタイマーが開始する
Buttonの実行する処理の箇所に、関数startTimer()を記述します。
Button("START") {
// ここを追加↓
startTimer()
}
.font(.largeTitle)
しかし、ここでボタンを押しても画面上には何も反映されません。
タイマーの開始を画面に反映する
Text("180")にremainingTimeの値が反映されるために次のように書き換えてください。
var body: some View {
ZStack {
Color.black
.ignoresSafeArea()
VStack(spacing: 24) {
Text("3分間カップラーメンタイマー")
.font(.title3)
.bold()
.foregroundStyle(.white)
// ここを変更↓
Text("\(remainingTime)")
.font(.system(size: 60))
.fontWeight(.black)
.foregroundStyle(.yellow)
Button("START") {
startTimer()
}
.font(.largeTitle)
}
}
}
残り時間が180.000000という値になってしまいましたが、画面上に反映されました。

実際にSTARTボタンを押すと、残り時間が減っていくのを確認できます。

