Speedometers are much simpler than GPS navigation apps, but they rely on the same
CoreLocation framework. Create a new blank SwiftUI app project in Xcode, right click the Info.plist file and select Open As > Source Code. Add the following at the end before the closing </dict> and </plist> tags:
<key>NSLocationWhenInUseUsageDescription</key> <string>GPS is needed to calculate speed</string>
You are required to add a string to explain your use of GPS to the user, and you will not be allowed to submit an app to the App Store that uses location services without it.
Now we can start with some simple extensions.
The string extension is just a way to make a string constant accessible to us later, when we’ll be using this as a key for a value stored in
UserDefaults. Then we have a complicated bunch of optional chaining as a return value for speed when multiplied by a multiplier. As our app will allow KPH or MPH as units, we want to multiply our value to convert it to these units. The actual value will be in metres per second, so it won’t be very useful as it is.
We’re using optional chaining because there may not be a known location, in which case we want the speed to be zero.
The other function is only called once. It sets the delegate, requests GPS access from the user, and then starts getting updates that relate to the user’s location. Since this is just a
CLLocationManager, and not the delegate we’re going to create, the logic for what to do when the location changes isn’t contained here. Instead we’re going to create an
ObservableObject, which I’ll call
We have a singleton instance called
shared, which I’ll be using in my SwiftUI.
We have the
CLLocationManager and the multiplier it will need depending on the units the user has chosen. When the location is updated, we get the speed value and use it to update a
Published property. This is what we’ll be displaying in our SwiftUI. You might also notice that
isKPH is a
Published property, which sets a bool in
UserDefaults whenever it is changed. The
speed property is also marked as
private(set), meaning that our SwiftUI (or any other object) cannot modify this value.
The finishing touch is a simple interface that will display our speed in a very large font. Although the font size is set to 400, we have a minimum scale factor of 0.2, meaning the font will be able to shrink to the size of a phone screen. We also have a
Toggle for changing the units, and this will save the preference for the next time the app is launched. Since no colours were specified, this app automatically adapts to light or dark mode, which is a bonus.