Tuesday, April 17, 2018

Pace Calculation in Swift

I need to add a new feature to show pace in my iOS App(TapToCount -3W). By given two dates and two locations as input, the pace can be easily calculated in the formula:

pace = duration / distance


In swift the duration can be obtained in following codes:

// dt1 and dt2 are Date types
let timeInterval = dt2.timeIntervalSince(dt1)

The func timeIntervalSince call will return seconds as time interval between two days.


The distance between two locations is obtained

// loc1 and loc2 are CLLocation type
let dist = dist2.distance(from: dist1)

where dist is the distance value in meters.

Support Localization and Accessibility

It seems that the pace calculation is so simple to get. Hold on. iOS provides APIs to support metric or imperial measurement system. It would be nice to get pace calculation result either in metric or imperial system. This can be easily detected by the following codes.

let locale = NSLocale.current
let metricSystem = locale.usesMetricSystem

In my iOS app, I presented the pace calculation result in human readable format. For example, 6'34" would be "6 min, 28 secs".

Further more, the pace result may be in hours, or even years, depending on inputs of dates and locations. My pace calculation is more generic to support a wide range of cases. To obtain readable result, it can be done by using Swift codes:

1 let fm = DateComponentsFormatter()
2 fm.allowedUnits = [.year, .day, .hour, .minute, .second]
3 fm.unitsStyle = .short
4 let short = fm.string(from: value)
5 fm.unitsStyle = .full
6 let full = fm.string(from: value)

The allowedUnits property specifies what readable units should be used. Here is the complete units from seconds to years, and only first none zero value's unit will be presented, for example, 2 hrs, 15 min, 23 secs. This example is in a short form. There is no need to worry about languages. The API will do the localization automatically. Very nice!

The short form is good for UI presentation. The full form will spell out whole units, such as "2 hours, 15 minutes, 23 seconds". This would be great for accessibility support, for example, label's accessibilityValue. The localization for full form is done automatically as well.

I tested this pace calculation in my iOS app. The following is the screenshot of my mountain hiking, Ha Ling Peak, last Sunday.

and this is my running result today when I was doing my test.

and here is one more test I did. I changed the iPhone language to Traditional Chinese.

You may notice that when the pace result is in years or long days, the last units minute and second are dropped out, since such small amount is so insignificant.  The complete codes are available in my answer in StackOverflow discussion.