In this post, we are going to make a count up timer using Swift and SwiftUI. This will walk you through step by step from making a new app to running the finished timer.
The finished project can be cloned from GitLab here.
Launch a new project in Xcode. The template needs to be a Single View App. The language needs to be set to Swift and the User Interface needs to be set to SwiftUI. You can set the
Product Name to be whatever you'd like. I'm calling mine Count Up Timer.
Let's add variables to hold the hours, minutes, and seconds that are needed to be displayed on the screen.
ContentView.swift, add lines 6 through 8 in the gist below.
These three variables,
seconds are declared with the
@State property wrapper so that the text updates when the value updates. You can read more about the
@State property wrapper here on Apple's website.
Now, let's actually design the UI. It's going to have the timer in the middle, then buttons to start/pause the timer and to reset the timer back to 0.
The first thing we need to do is add a VStack in the
body. To do this, you can right click on the
Text("Hello, World!") and choose Embed in VStack. Your code should now look like the gist below.
Then, we need to put the variabled in. We are going to change the
Hello, World! to
\(hours):\(minutes):\(seconds). If you open the Canvas and resume it, then you should see 0:0:0 in the device.
You might be asking why use
\() around the variable name. The slash and parenthesis are needed to tell the compiler that there is code inside the parenthesis. Therefore, the program will display the contents of the variable and not the variables name.
Now, let's add the buttons and make them do something!
First, we are going to add a new state variable that signifies if the timer has started or been paused. Right after the declaration of
@State var timerIsPaused: Bool = true.
Text() we need to add an if statement that is going to show a view when the timer is paused and when it's going. The gist below shows what the view should look like with that if statement.
Now, we are going to change Text to Buttons and use SF Symbol for Start, Pause, and Reset.
timerIsPaused is true, then we want to show a play icon for start and a backward icon for reset. To do this, we need to use the
Image(systemName: String) as the Button labels. These two buttons also need to be in a HStack to be next to each other. Now, if
timerIsPaused is false, we need to show a pause icon to stop the timer. The gist below shows the buttons in the if statement.
That's what it took to "design" this app in SwiftUI. Next, we are going to make the parts functional.
It's time to actually get the timer going. We are going to use the
Timer that's buit into Swift. We will need to make a repeating timer that adds one second every second.
Let's add a variable for the state first, so after
@State var timer: Timer? = nil. This declares a variable to store the timer in, but doesn't actually store a Timer to the variable, yet, since we will call a new Timer when the timer starts.
Next we need to write a function that starts the timer and changed
timerIsPaused to false. The function is going to be called
startTimer(). In the function, add the line
timerIsPaused = false. After that, a timer needs to be added, so the gist below shows that.
Now, I'm going to explain what's going on in lines 3 thourgh 5.
This is where a new timer is actually made. I'm using a scheduled Timer so that every second something can be triggered.
withTimeIntervalis used to specify how often, in seconds, each action inside the closure is executed. I have it set to 1, so that seconds is incremented each second.
repeatsneeds to be set to true so that the code in the closure is ran every 1 second. If it is set to false, then the operations in the closure is only ran one time.
This is all the code to check when to increment seconds, minutes, and hours.
I chose to use the closure method of starting a new timer so that I didn't have to wrap the function in an objective-c caller.
Once the function is written, make sure to call it in the button. Here is what the Start button code should now look like.
It's time for another function to actually stop the timer. The function is going to be called
stopTimer(). In this timer, we need to set
timerIsPaused to false and kill the timer that is currently running. To kill the timer, we call the
invalidate() function on the timer, which will not allow the timer to fire again. Here is what the function looks like.
Now, make sure to call the function when the Stop button is pressed.
Here is what
ContentView.swift should look like at this point.
This is the easiest function. It's going to set
seconds back to 0.
Now, call it when the reset button is pressed using
Now the count up timer is done. You should be able to run the app, start the timer, stop the timer, and reset it.
The completed project can be cloned from GitLab.
If you enjoy my posts, streams, and apps, consider encouraging my efforts.