Swift Swift: Using NSTimer to Make a Timer or Alarm

With the launch of the Apple Watch it’s time for timers in iOS and WatchKit. Learning to use timers is a very important skill for most developers. There are many places we need to schedule regular intervals of time to do things. In my WatchKit series I’m writing a workout interval timer which tells the user when to switch intervals. Timers can tell the system to do more than just alarms. If you are not using SpriteKit, Games and animations need the use of timers to control the frames per second of animation. In this lesson, we’ll look at NSTimer, and what we can do with the timer. There are two ways most people use it: for a single event or for repeated events. We’ll discuss both.

Set up the Storyboard

Create a new Project named SwiftPizzaTimer in a single view template with Swift as the language. Drag three labels, three buttons and a switch to the storyboard. Arrange the storyboard like this.

You can use Auto layout in the Width:any Height:any size class, or set you size class to Width:compact, height:any and just drag and drop your controls. To use auto layout, do the following:
Drag one label to the storyboard. Title it Pizza Timer. Give it a light gray background with black letters, center alignment and a font size of 46 point. Pin the label 0 points up 0 left and 0 right. Set the height to 64 points, and select to Update the frame of new Constraints.
Drag two buttons under the label and next to each other. On the button to the left, title it Start, make the font black with a size of 46 points and a green background. On the right title the label Stop with a size of 46 points, white lettering and a red background. Pin the Start label 15 points up, and 0 left. Do not update the frames. Pin the Stop label 0 left and 0 right. Select the Pizza Timer label and the Start button. In the pin menu select Equal Heights. Select the Start button and the Stop button. In the pin menu, select Equal widths and Equal Heights. In the align menu with both Start and Stop still selected, select Top edges, and make sure the value is 0. Also select the Update Frames Items of New Constraints.

Drag another button to the storyboard. Label it Reset, with a blue background, white lettering, and a font size of 46 points. Pin the Reset button 0 left,0,right, 20 down, but do not update constraints yet. Select both the Pizza Timer label and the Reset button and in the pin menu select Equal Heights and set Update Frames to Items of New Constraints.

Drag a switch to the storyboard. Set its state to off in the attributes inspector. In the align menu, Align the switch to Horizontal Center in Container. Pin the Switch 15 up and select for Update Frames Items of new Constraints.

Drag two more labels to the storyboard position one to the left of the switch labeled Up and one to the right Down. Give both a font color of White and a font of 36 points. Right justify the Up label. pin the Up Label 0 left and 15 right. Select the label and the switch, and in the align menu Align to centers, and Update Frames of new constraints. Select the down label. Pint the down label 15 left and 0 right. Select both the Down label and the switch. In the align menu Align to centers, and Update Frames of new constraints. Your finished layout should be this:

Open the assistant editor and control-drag the outlets and actions. Start with the Pizza Timer label. Control drag and make an outlet timerLabel.

@IBOutlet weak var timerLabel: UILabel! //label on top of the view

From the switch make an outlet countingDown

@IBOutlet weak var countingDown: UISwitch! //for use in iteration 2

From the three buttons control drag to make three actions: startTimer, stopTimer and resetTimer respectively:

The first parameter gives a time in seconds that the timer will run for. At the end of that time, it will call a method set by the second two parameters. If there is information that needs passing to that method, we do so in the userInfo parameter, which stores the information in the timer. Often this will be a dictionary of several values, though it can be any object. The last parameter tells us if we will repeat the timer or just end.

Our timer schedules a time of timeInterval, and when done runs a method timerDidEnd, then stops. This is the classic alarm clock method of doing something. You set an alarm and it goes off at some time with a given message, then dies. Xcode complains we have not defined interval or timer. Just below your outlet declarations add this

When the timer fires, It calls this method. We tell the user that the timer completed with the Pizza Ready!! message. Because we set repeat to false, the timer will dismiss itself after this call. If we need any information about the timer, including whatever we stored in userInfo, we have a parameter in our method to access it, which we have our completion message. Since userInfo is of type AnyObject, we will need to downcast it correctly before use.

In our stopTimer method, we use the NSTimer method invalidate to stop and destroy the timer. Once stopped, the app gives the user feedback to tell them the timer stopped.

Build and run. When the app loads, tap the start button. nothing happens for ten seconds, when you get this:

Using Repeating Timers

Timers only show that a time event happened. In the example above that was pretty boring. Let’s change the code for more user feedback and have the timer count up or down the ten seconds of our timer. To do this, we’ll use the most common way of using a timer with repeat set to true. The strategy here is having lots of short timing events. At each time event we do some updating and check if we are at our target time, when we will shut down our timer and do our exit activities like we did with our first example.

The timer is the same, but we changed our interval to 0.05 seconds. every 0.05 seconds we will update the timerLabel with a new time. There is a balance here, which you might want to experiment with. If you make too big an interval, there will be inaccuracy with your visible timer. If you make too small an interval, you use a large amount of resources. If you use too many, you might have an internal inaccuracy to your timer as well and the app will be unresponsive. My general rule is to set my interval for a half of the last digit of accuracy you are displaying. I am going to 0.1 seconds accuracy on my label, so I set the interval to 0.05.

Since interval is no longer telling me when ten seconds is up we need another constant to tell us that, assigned to timerEnd. I also assigned a variable timeCount. Every time timer fires, the app will either add or subtract the timeInterval from timeCount. When I reach zero on a countdown timer or 10 on a count up timer I stop. Change your timerDidEnd method to this:

We use the switch countingDown to decide if we count up or down. If we count up, we add the time interval. If counting down, we subtract the time interval. We look for our ending condition. If true, we exit as we defined it in the last example. If not at the ending condition, we update the time display.

The time is in seconds, We need to format it to a form usable by most humans, which we do in the function timeString. Add this code:

We use the truncation power of integers to get minutes and seconds we can use in our return string of mm:ss.s. minutes takes a timeinterval of seconds and makes it an integer then divides by 60 seconds. seconds subtracts out that many seconds. We get a digit for the tenth of a second by subtracting the number of seconds from the integer number of seconds.

We now have a display when the timer fires. We have not yet implemented a reset for the timer. Add this to your code:

Depending on the switch, we have a different starting point. Counting down, we count down from timerEnd to 0. We do the reverse for counting up, starting at 0. Now that we have a reset function, we can define the action for the reset button.

We changed the timer to be a repeating timer by changing repeats to false. We can build and run.

We have a working timer. You can change the countdown or count up by tapping the switch.

One more bug — Using Flags in Timers

It’s important for debugging to check all possibilities of use. If we reset the timer, then change our count direction, the timer fails. The timer believes it is already done. When we reset, we clear the counter. When we change the switch, we change the terminating value to be the same as the start value and the timer thinks it’s finished. We’ll need to change our start value when the switch changes and the timer is reset.

Go to the storyboard and open the assistant editor. Control drag from the switch to the code. Make a new action countingDown. Add the following code to the action:

We use a flag isTiming to decide if the timer is in the middle of a count. If it is not, which will happen after the timer is done or a reset and when we change the switch we reset the count. Otherwise we leave the count alone. Flags in timer are common. they are good ways of indicating the state of the timer while it is running repetitively, much in the same way valid works for a single timer. We still need a little setup for this to work. Add the variable to our properties at the top of the class:

var isTiming = false

In starTimer, add isTiming = true to the if clause code block and isTiming = false to resetTimer, and just under the two timer.invalidate() in timerDidEnd
Build and run. Now the timer works right.

My watch is still in the queue for delivery, so I have not tested it. However, most of the extension code runs and stays on the phone, not the watch. For developers, the watch is literally and figuratively an extension of the phone. Basically, You are not running apps on the watch, just the view of MVC. The model and controller are on the phone. NSTimer should happily work away even if the watch sleeps.

I’ve been building a timer app but am searching for a way to alert or alarm when the timer is done. In your example, if someone isn’t staring at the watch, how will they know it’s pizza time? Everything I’ve read says that you can’t activate the taptic engine. Is the only option to throw a notification and generate a glance? Seems like an obvious thing for a watch to do. In the default stopwatch app on Watch it will notify you, but those must be private APIs.

I really appreciate this series of blog posts, and any help you can offer.
Thanks.

At this point,and to my knowledge, a notification is the only way to go. Another one of those things I’d like to see introduced at WWDC2015 in early June ( not to mention my watch getting delivered ). As soon as I get through the foundation classes, I’ll cover notifications.

depends if you want fractions of seconds or integer seconds. I’ll give you the integer version (which can be expanded to days, weeks, years, etc) and leave this as a hint for the fractional one. All you are doing is diving by the number of seconds in some time period. The whole part of that division is the number of that time period. The remainder you use in the next calculation down.

What would be the framework or library to use to set up an alarm clock in Swift? I want to be able to hit an image in my app and go to a page that has three selections on a alarm to set. Like 3 days 6 hours, 4 days, 5 days 8 hours. User clicks one and Alarm is set which will notify in said amout a of time. Ns timer goes off in background I realize so that is out so how would I go about that?

Post navigation

Subscribe to A Slice of App Pie Newsletter

If you are making your own stuff, doing your own work and trying to sell it in the market, most advice isn't enough. You want it to work. You want to sell your works to those who most are touched by them. This newsletter is for you. I am one of those people like you, creative, independent and maybe a little bit crazy to the outside world. I'll talk about writing good apps for Apple platforms, the tools and API's to get there. Along the way I will show you how to become you best creative self. I will show you how to build and create, and make some money at it too.

Get exclusive content, new post notifications, tips and more in A Slice of App Pie.

Archives

Archives

Current Published Works

Pratical Autolayout for Xcode 8

In Practical Auto Layout for Xcode 8, using simple, practical, easy to follow examples, you will learn how to master auto layout, size classes and stack views on the Xcode 8 storyboard. Using easy to follow examples, you will learn how to make universal apps quickly easily and in far less time than ever before.

Swift Swift: View Controllers

You will learn to use auto layout, size classes and new Swift implementations of view controllers. With plenty of color illustrations and code snippets, Swift Swift View Controllers will take you step by step through many easy demonstrations, teaching you the stuff you really need to know to implement any of these view controllers.