Creating a Simple Watch Timer App in SwiftUI Part 1
Tags: beginners, tutorial
Published: 2022-02-23 23:27:38

_(This blog post's cover photo has been designed using resources from Freepik.com)_


By bringing together SwiftUI and Combine, we can create a simple watch timer app that will add a little amount of pressure to any user. Its implementation is simple, so let's get started.

This is what our app will look like at the end of this short tutorial:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4r1us1du42um1pcgih8.gif)

---

## Step 1: Setting Up a New watchOS Project

To create a new _watchOS_ project:

1. In Xcode, choose File > New > Project.
2. Go to the _watchOS_ tab.
3. Choose _Watch App_ as the template of your new project and click Next. 

In the project options, enter the name for your project (I named mine "SimpleTimerApp" 😎). Ensure that the Language is set to _Swift_. 

Once you click _Next_, you will be asked to select a location to save your project. Click _Create_. 

![Watch App Project Template](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98v14mwh8mbgt1oqd61v.png)

![Project Options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mhfyo3195fmy1fqqupo7.png)

---

## Step 2: Declaring our State variables

For this, we can use the default _ContentView.swift_ file. Let's first create our two state variables:

1. 'count' (represents our time in seconds)
2. 'timer' (represents our countdown timer)

```
@State private var count = 0
@State private var timer: Timer?
```

When we use **@State** (a property wrapper), we’re asking SwiftUI to watch a property for changes. So if we add 1 to our _count_ variable, for example, our State will see this and re-render the view. If there is a change in the state of this property, we will see the number on our screen update.

To make a countdown timer or similar, we will use **Timer**. For our needs, we'll use an optional variable to set the timer to nil at the start. Our timer will be set at a later time.

---

## Step 3: Defining our SwiftUI Stacks

Using stacks in SwiftUI allows us to arrange our UI elements. We will need two type of stacks in this project: 

- _VStack_ - arranges UI elements in a vertical line, i.e above or below each other.
- _HStack_ - arranges elements in a horizontal line, i.e. beside each other. 

```
var body: some View {
        VStack(alignment: .center, spacing: 8){
            Text("Hello, World!")
                .padding()
            
            HStack(alignment: .center, spacing: 8){
                //Increment button
                //'Go' button
            }
        }
    }
```

We will further customize our stacks with alignment and spacing in order to modify their appearance. For example, our _VStack_ elements will be aligned horizontally in the middle and 8 points apart. Our _HStack _elements will be aligned vertically in the middle and 8 points apart as well.

---

## Step 4: Preparing our UI elements 🎨

Replace the string "Hello Word" with "0" as a placeholder text for our _count_. We will also increase the font size and font weight of this string.

```
Text("\(count)")
    .font(.system(size:90))
    .fontWeight(.bold)
```

Now, let's set up our two buttons in our _HStack_:

1. Increment button: Adds 1 to the _count_ variable every time the button is pressed. As a styling preference, we are rendering the _plus_ icon from _SF Symbols_ using **Image**.

2. 'Go' button: This is where we will start our countdown timer. For styling, we will make the text a green colour.

```
//Increment button

Button {
  count = count + 1 
} label: {
  Image(systemName: "plus") 
    .font(.system(size:34))
}

//'Go' button

Button {
  //set our countdown timer
} label: {
   Text("Go!")
      .font(.system(size:34))
      .foregroundColor(.green)
}
```

---

## Step 5: Starting our Countdown Timer

Once a user clicks on the 'Go!' button, we want our timer to start counting (in seconds) all the way down to 0. However, we want to ensure that our _count_ is neither equal to nor less than 0. We will only start our timer if our _count_ value is greater than 0. 

```
Button {
    
    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {time in
        if count > 0 {
            count -= 1
        }else {
          timer?.invalidate()
        }
    }
    
}label: {
    Text("Go!")
        .font(.system(size:34))
        .foregroundColor(.green)
    
}
```

You can destroy an existing timer by calling its **invalidate() **method. In this case, the timer is destroyed until it is restarted. If the _count_ value was increased a second time, the timer will not begin until the user presses the 'Go' button.

---

## Overview

And that's it! Below, you will see the finished code structure of this simple app. Thank you for reading!

```
import SwiftUI
import Combine

struct ContentView: View {
    
    @State private var count = 0
    @State private var timer: Timer?
    
    var body: some View {
        VStack(alignment: .center, spacing: 8){
            Text("\(count)")
                .font(.system(size:90))
                .fontWeight(.bold)
            
            HStack(alignment: .center, spacing: 8){

                //Increment button
                Button {
                    count = count + 1 //add 1 to the count variable each time the button is pressed
                } label: {
                    Image(systemName: "plus") //rendering an icon from SF Symbols
                        .font(.system(size:34))
                }
                
                Button {
                    
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {time in
                        if count > 0 {
                            count -= 1
                        }else {
                          timer?.invalidate()
                        }
                    }
                    
                }label: {
                    Text("Go!")
                        .font(.system(size:34))
                        .foregroundColor(.green)
                    
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```