# Chapter 4. Measurements and Units

We’ve all been there! You need to convert one unit to another, and you begin your journey, most of the time, by Googling what the conversion should be. You can now use some built-in structures to represent and convert your units.

The following classes and structures appear throughout this chapter:

`Unit`

- The base class for all the units that are in the SDK itself. This class defines a symbol for the unit, such as
`m`

for meters. `Dimension`

- The class that inherits from
`Unit`

and defines the converter to be used between various units. `UnitLength`

,`UnitMass`

, and the like- Basic units that inherit from
`Dimension`

. Each unit offers alternative ways of representing a particular measure, such as length or mass. Each unit also standardizes the various symbols for its measure, such as`m`

for meters,`km`

for kilometers, and`smi`

for Scandinavian miles (with each Scandinavian mile being equal to 10 kilometers). - Measurement
- The base structure for defining a value with a unit. Every measurement has a value of type
`Double`

and a unit of type`Unit`

.

# 4.1 Converting Between and Working with Length Units

## Solution

Follow these steps:

- Represent your values first by constructing instances of
`Measurement`

with your given value. Use one of the units defined in`UnitLength`

as the unit for your measurement, such as`UnitLength.meters`

. - After you have your
`Measurement`

instances, you can use the various operators such as`+`

and`-`

between them as long as they are from the same base unit. - You can also use the
`converted(to:)`

function of your`Measurement`

structure instances to convert your values to another unit type of the same base unit. For instance, converting meters to miles is fine, as they are both from the`UnitLength`

base unit, but converting kilometers to hours is not going to work because hours are represented by the`UnitDuration`

unit.

## Discussion

Your values are representable by instances of the `Measurement`

structure with a given unit. Let’s create two values, one for 5 meters and the other for 1 kilometer:

`let`

`meters`

`=`

`Measurement`

`(`

`value`

`:`

`5`

`,`

`unit`

`:`

`UnitLength`

`.`

`meters`

`)`

`// 5.0 m`

`let`

`kilometers`

`=`

`Measurement`

`(`

`value`

`:`

`1`

`,`

`unit`

`:`

`UnitLength`

`.`

`kilometers`

`)`

`// 1.0 km`

You can then check out the return value of `type(of:)`

on these values to see what data type they have:

`type`

`(`

`of`

`:`

`meters`

`)`

`// Measurement<UnitLength>`

`type`

`(`

`of`

`:`

`kilometers`

`)`

`// Measurement<UnitLength>`

Their data type is `Measurement`

, which itself is generic, and its generic parameter is set to `UnitLength`

since both values are lengths.

You can then simply add these values together if you want:

`let`

`result`

`=`

`meters`

`+`

`kilometers`

`// 1005.0 m`

`type`

`(`

`of`

`:`

`result`

`)`

`// Measurement<UnitLength>`

This `+`

operator is defined in the Foundation framework as follows:

`public`

`func`

`+<`

`UnitType`

`:`

`Dimension`

`>(`

`lhs`

`:`

`Measurement`

`<`

`UnitType`

`>,`

`rhs`

`:`

`Measurement`

`<`

`UnitType`

`>)`

`->`

`Measurement`

`<`

`UnitType`

`>`

Eventually, you can convert the result into various other units of length, such as miles:

`let`

`finalKilometers`

`=`

`result`

`.`

`converted`

`(`

`to`

`:`

`.`

`kilometers`

`)`

`// 1.005 km`

`let`

`finalMeters`

`=`

`result`

`.`

`converted`

`(`

`to`

`:`

`.`

`meters`

`)`

`// 1005.0 m`

`let`

`finalMiles`

`=`

`result`

`.`

`converted`

`(`

`to`

`:`

`.`

`miles`

`)`

`// 0.6224 mi`

`let`

`finalScandinavianMiles`

`=`

`result`

`.`

`converted`

`(`

`to`

`:`

`.`

`scandinavianMiles`

`)`

`// 0.1005 smi`

If you wish to present these values to the user, which are of type `Measurement<Unit>`

, read the `value`

and the `unit.symbol`

properties from them. The `value`

will be of type `Double`

and the `unit.symbol`

of type `String`

. This gives you the information you need to display values on UI components, such as a `UILabel`

instance.

## See Also

# 4.2 Working with and Switching Between Angle Units

## Solution

Just like length units (see Recipe 4.1), values that represent an angle can also be encapsulated inside an instance of the `Measurement`

structure. The unit is `UnitAngle`

.

## Discussion

Let’s have a look at how you can represent 100 gradians in your application:

`let`

`gradians`

`=`

`Measurement`

`(`

`value`

`:`

`100`

`,`

`unit`

`:`

`UnitAngle`

`.`

`gradians`

`)`

`// 100.0 grad`

You can then convert this value to degrees using the `convert(to:)`

function of the `Measurement`

structure:

`gradians`

`.`

`converted`

`(`

`to`

`:`

`UnitAngle`

`.`

`degrees`

`)`

`// 90 degrees`

And if you read the return value of `type(of:)`

on this value, you will get the value of `Measurement<UnitAngle>`

:

`type`

`(`

`of`

`:`

`gradians`

`)`

`// Measurement<UnitAngle>`

Similarly, you can represent degrees with the `Measurement`

structure:

`let`

`degrees`

`=`

`Measurement`

`(`

`value`

`:`

`180`

`,`

`unit`

`:`

`UnitAngle`

`.`

`degrees`

`)`

`// 180.0`

And just like the `+`

operator we saw used before with `Measurement`

types, you also have a `-`

operator that is defined like so:

`public`

`func`

`-<`

`UnitType`

`:`

`Dimension`

`>(`

`lhs`

`:`

`Measurement`

`<`

`UnitType`

`>,`

`rhs`

`:`

`Measurement`

`<`

`UnitType`

`>)`

`->`

`Measurement`

`<`

`UnitType`

`>`

You can use this operator between any two instances of the `Measurement`

structure as long as their base units are the same:

`let`

`total`

`=`

`gradians`

`-`

`degrees`

`// -90 degrees`

Once you have your angle measurements, you can convert them to each other:

`let`

`finalGradians`

`=`

`total`

`.`

`converted`

`(`

`to`

`:`

`.`

`gradians`

`)`

`// -100 grad`

`let`

`finalDegrees`

`=`

`total`

`.`

`converted`

`(`

`to`

`:`

`UnitAngle`

`.`

`degrees`

`)`

`// -90 degrees`

Additionally, you can show this value to your users with the `value: Double`

and `unit.symbol: String`

properties of your `Measurement`

instance:

`let`

`string`

`=`

`"`

`\(`

`finalDegrees`

`.`

`value`

`)`

`\(`

`finalDegrees`

`.`

`unit`

`.`

`symbol`

`)`

`"`

`// "-90 degrees"`

## See Also

# 4.3 Representing and Converting Between Durations of Time

## Solution

To solve this problem, instantiate the `Measurement`

structure with your time values and use the `UnitDuration`

for your base unit. You can then use `+`

, `-`

, and other basic operators between your units without worrying about what unit they are represented with, as long as they come from the `UnitDuration`

base unit.

## Discussion

Let’s have a look at an example of how we can convert hours, minutes, and seconds to one another, but let’s spice it up a little bit. It’s clear that we can use `Measurement`

to represent all three values with `UnitDuration`

, but we can instead extend `Double`

so that any number can then be turned into an hour, minute, or second value represented by `Measurement`

:

`extension`

`Double`

`{`

`var`

`hours`

`:`

`Measurement`

`<`

`UnitDuration`

`>{`

`return`

`Measurement`

`(`

`value`

`:`

`self`

`,`

`unit`

`:`

`UnitDuration`

`.`

`hours`

`)`

`}`

`var`

`minutes`

`:`

`Measurement`

`<`

`UnitDuration`

`>{`

`return`

`Measurement`

`(`

`value`

`:`

`self`

`,`

`unit`

`:`

`UnitDuration`

`.`

`minutes`

`)`

`}`

`var`

`seconds`

`:`

`Measurement`

`<`

`UnitDuration`

`>{`

`return`

`Measurement`

`(`

`value`

`:`

`self`

`,`

`unit`

`:`

`UnitDuration`

`.`

`seconds`

`)`

`}`

`}`

Now that this is done, we can put together a few values using these properties:

`let`

`trainJourneyDuration`

`=`

`(`

`1.25`

`).`

`hours`

`trainJourneyDuration`

`.`

`converted`

`(`

`to`

`:`

`.`

`minutes`

`)`

`// 75.0 min`

`let`

`planeJourneyDuration`

`=`

`(`

`320.0`

`).`

`minutes`

`planeJourneyDuration`

`.`

`converted`

`(`

`to`

`:`

`.`

`hours`

`)`

`// 5.333 hr`

`let`

`boatJourneyDuration`

`=`

`(`

`1500.0`

`).`

`seconds`

`boatJourneyDuration`

`.`

`converted`

`(`

`to`

`:`

`.`

`minutes`

`)`

`// 25.0 min`

These values each represent a sub-journey of a bigger journey from one destination to another and they are in minutes, hours, and seconds. We can put them all together inside an array and calculate their total value in minutes, using each `Measurement`

instance’s `convert(to:)`

method:

`let`

`journeys`

`=`

`[`

`trainJourneyDuration`

`,`

`planeJourneyDuration`

`,`

`]`

`let`

`finalJourneyDurationInMinutes`

`=`

`journeys`

`.`

`reduce`

`(`

`0.0`

`){`

`return`

`$0`

`+`

`$1`

`.`

`converted`

`(`

`to`

`:`

`UnitDuration`

`.`

`minutes`

`).`

`value`

`}`

`finalJourneyDurationInMinutes`

`// 395`

Representing time with `Measurement`

makes it much easier to work with existing classes such as `Timer`

. For instance, if you want a timer that runs for *n* seconds, all you have to do is create a `Measurement`

instance of type `UnitDuration.seconds`

and then, once the measurement’s `value`

property is less than or equal to 0, you can invalidate the timer:

`import`

`UIKit`

`import`

`PlaygroundSupport`

`PlaygroundPage`

`.`

`current`

`.`

`needsIndefiniteExecution`

`=`

`true`

`extension`

`Double`

`{`

`var`

`seconds`

`:`

`Measurement`

`<`

`UnitDuration`

`>{`

`return`

`Measurement`

`(`

`value`

`:`

`self`

`,`

`unit`

`:`

`UnitDuration`

`.`

`seconds`

`)`

`}`

`}`

`var`

`remainingTime`

`=`

`Measurement`

`(`

`value`

`:`

`10`

`,`

`unit`

`:`

`UnitDuration`

`.`

`seconds`

`)`

`Timer`

`.`

`scheduledTimer`

`(`

`withTimeInterval`

`:`

`1.0`

`,`

`repeats`

`:`

`true`

`)`

`{`

`timer`

`in`

`let`

`minutesRemaining`

`=`

`remainingTime`

`.`

`converted`

`(`

`to`

`:`

`UnitDuration`

`.`

`minutes`

`)`

`(`

`"`

`\(`

`minutesRemaining`

`.`

`value`

`)`

`minutes remaining before the timer stops"`

`)`

`remainingTime`

`=`

`remainingTime`

`-`

`(`

`1.0`

`).`

`seconds`

`if`

`remainingTime`

`.`

`value`

`<=`

`0.0`

`{`

`timer`

`.`

`invalidate`

`()`

`}`

`}`

###### Note

The `PlaygroundSupport`

framework is used alongside the `PlaygroundPage.current.needsIndefiniteExecution: Bool`

property, which you can set to `true`

if you need an infinite loop in your playground so that your playground doesn’t just start at one point and end at another. In contrast with the default behavior of playgrounds, starting at the top and ending after the execution of the last line of code in the playground, yours becomes a fully fledged application that lives until you ask it to stop.

# 4.4 Using and Working with Frequency Units

## Solution

Represent your values with the `Measurement`

structure and use `UnitFrequency`

as the base unit. The `UnitFrequency`

class has various class variables such as:

`terahertz`

`gigahertz`

`megahertz`

`kilohertz`

## Discussion

If you build computers in your spare time (as I used to do more frequently, before I had three children!), you’ll see keywords such as megahertz and gigahertz all over the place. It’s a great idea to represent all these values with some structure in Swift, and with `Measurement`

now you can do that by choosing `UnitFrequency`

as your base unit.

Here is an example of representing two CPU clock speeds in Swift, using gigahertz and then megahertz:

`var`

`myCpuClock`

`=`

`Measurement`

`(`

`value`

`:`

`3.5`

`,`

`unit`

`:`

`UnitFrequency`

`.`

`gigahertz`

`)`

`var`

`yourCpuClock`

`=`

`Measurement`

`(`

`value`

`:`

`3400`

`,`

`unit`

`:`

`UnitFrequency`

`.`

`megahertz`

`)`

You can then use the built-in `>`

and `<`

operators to see which values are bigger or smaller:

`if`

`myCpuClock`

`>`

`yourCpuClock`

`{`

`"My CPU is faster than yours."`

`}`

`else`

`if`

`yourCpuClock`

`>`

`myCpuClock`

`{`

`"Your CPU is faster than mine. Good for you!"`

`}`

`else`

`{`

`"It seems our CPU clocks are the same!"`

`}`

These two operators are defined for you already in the Foundation framework so that you don’t have to write them yourself:

`public`

`func`

`><`

`UnitType`

`:`

`Dimension`

`>(`

`lhs`

`:`

`Measurement`

`<`

`UnitType`

`>,`

`rhs`

`:`

`Measurement`

`<`

`UnitType`

`>)`

`->`

`Bool`

`public`

`func`

`<<`

`UnitType`

`:`

`Dimension`

`>(`

`lhs`

`:`

`Measurement`

`<`

`UnitType`

`>,`

`rhs`

`:`

`Measurement`

`<`

`UnitType`

`>)`

`->`

`Bool`

Now that you have two CPUs whose clock speeds are represented in various forms of the frequency unit, you can put them inside an array and iterate through this array to get their clock speeds shown in gigahertz:

`let`

`baseUnit`

`=`

`UnitFrequency`

`.`

`gigahertz`

`[`

`myCpuClock`

`,`

`yourCpuClock`

`].`

`enumerated`

`().`

`forEach`

`{`

`offset`

`,`

`cpuClock`

`in`

`let`

`converted`

`=`

`cpuClock`

`.`

`converted`

`(`

`to`

`:`

`baseUnit`

`)`

`(`

`"CPU #`

`\(`

`offset`

`+`

`1`

`)`

`is`

`\(`

`converted`

`.`

`value`

`)`

`\(`

`converted`

`.`

`unit`

`.`

`symbol`

`)`

`"`

`)`

`}`

And the output will be as shown here:

CPU #1 is 3.5 GHz CPU #2 is 3.4 GHz

## See Also

# 4.5 Working with and Using Power Units

## Solution

Simply use `Measurement`

to represent your power units with the unit equal to `UnitPower`

and then use the `convert(to:)`

function of the `Measurement`

structure to convert your values to other power units, some of which are listed here:

`terawatts`

`gigawatts`

`megawatts`

`kilowatts`

`watts`

`horsepower`

## Discussion

Let’s check out an example. Let’s say that you are riding a bicycle and moving forward by putting 160 watts of energy into the pedals. Now, a super-duper cyclist that has won three Tour de France tournaments has a pedaling power of 0.40 horsepower. Are you putting more power into the pedals than this super cyclist, or the other way around? How can you find the answer without having to convert one of these values to the other or both values to another base unit?

Well, the answer is quite easy. Simply represent these values with `Measurement`

:

`let`

`myCyclingPower`

`=`

`Measurement`

`(`

`value`

`:`

`160`

`,`

`unit`

`:`

`UnitPower`

`.`

`watts`

`)`

`let`

`superCyclistPower`

`=`

`Measurement`

`(`

`value`

`:`

`0.40`

`,`

`unit`

`:`

`UnitPower`

`.`

`horsepower`

`)`

And then use the `>`

and `<`

operators that are already defined for you to find out which value is larger:

`if`

`myCyclingPower`

`>`

`superCyclistPower`

`{`

`"Wow, I am really strong."`

`}`

`else`

`if`

`myCyclingPower`

`<`

`superCyclistPower`

`{`

`"The super cyclist is of course stronger than I am."`

`}`

`else`

`{`

`"It seems I am as strong as the super cyclist!"`

`}`

But how does iOS do this, and how does it know how to compare these values? The answer is simple: base units. If you Command-click `UnitPower`

in Xcode, you will see some code like this:

`@`

`available`

`(`

`iOS`

`10.0`

`,`

`*`

`)`

`public`

`class`

`UnitPower`

`:`

`Dimension`

`,`

`NSSecureCoding`

`{`

`/*`

`Base unit - watts`

`*/`

There you can see that the base unit is watts. iOS converts all your power units to watts and then compares their `value`

properties to find which one is higher.

# 4.6 Representing and Comparing Temperature Units

## Solution

To avoid having to convert different temperature units, encapsulate your temperature values inside an instance of the `Measurement`

structure with the `UnitTemperature`

unit type. Then you can use the `convert(to:)`

method of the `Measurement`

structure to convert different types to each other and also use the existing greater-than, less-than, and other operators to manipulate or compare these measurements.

## Discussion

Let’s have a look at an example. Say that we have three temperatures of types Celsius, Fahrenheit, and Kelvin and our goal is to convert them all to Celsius and then sort them in ascending order. Let’s first represent our temperatures:

`let`

`cakeTemperature`

`=`

`Measurement`

`(`

`value`

`:`

`180`

`,`

`unit`

`:`

`UnitTemperature`

`.`

`celsius`

`)`

`let`

`potatoesTemperature`

`=`

`Measurement`

`(`

`value`

`:`

`200`

`,`

`unit`

`:`

`UnitTemperature`

`.`

`fahrenheit`

`)`

`let`

`beefTemperature`

`=`

`Measurement`

`(`

`value`

`:`

`459`

`,`

`unit`

`:`

`UnitTemperature`

`.`

`kelvin`

`)`

Next we can sort them by their Celsius values in an ascending order:

`let`

`sorted`

`=`

`[`

`cakeTemperature`

`,`

`potatoesTemperature`

`,`

`beefTemperature`

`]`

`.`

`sorted`

`{`

`(`

`first`

`,`

`second`

`)`

`->`

`Bool`

`in`

`return`

`first`

`.`

`converted`

`(`

`to`

`:`

`.`

`celsius`

`)`

`<`

`second`

`.`

`converted`

`(`

`to`

`:`

`.`

`celsius`

`)`

`}`

When we have a sorted array, we can convert all the values to Celsius to get our final sorted array of Celsius temperatures:

`let`

`allCelsiusTemperatures`

`=`

`sorted`

`.`

`map`

`{`

`$0`

`.`

`converted`

`(`

`to`

`:`

`.`

`celsius`

`)`

`}`

`allCelsiusTemperatures`

`// 93.33, 180, 185.8`

## See Also

# 4.7 Working with and Converting Volume Units

## Discussion

Imagine that you are baking a cake and three of the ingredients that you need are represented in different units, namely liters, deciliters, and pints:

`let`

`milk`

`=`

`Measurement`

`(`

`value`

`:`

`2`

`,`

`unit`

`:`

`UnitVolume`

`.`

`liters`

`)`

`let`

`cream`

`=`

`Measurement`

`(`

`value`

`:`

`3`

`,`

`unit`

`:`

`UnitVolume`

`.`

`deciliters`

`)`

`let`

`water`

`=`

`Measurement`

`(`

`value`

`:`

`1`

`,`

`unit`

`:`

`UnitVolume`

`.`

`pints`

`)`

You can add all these values together with the `+`

operator and convert the total to various other volumes, such as cups:

`let`

`total`

`=`

`milk`

`+`

`cream`

`+`

`water`

`let`

`totalDeciliters`

`=`

`total`

`.`

`converted`

`(`

`to`

`:`

`.`

`teaspoons`

`)`

`let`

`totalLiters`

`=`

`total`

`.`

`converted`

`(`

`to`

`:`

`.`

`tablespoons`

`)`

`let`

`totalPints`

`=`

`total`

`.`

`converted`

`(`

`to`

`:`

`.`

`cups`

`)`

You can also go through all the values and print their details, such as their raw values and the symbols that represent their units:

`func`

`showInfo`

`(`

`for`

`measurement`

`:`

`Measurement`

`<`

`UnitVolume`

`>){`

`let`

`value`

`=`

`measurement`

`.`

`value`

`let`

`symbol`

`=`

`measurement`

`.`

`unit`

`.`

`symbol`

`(`

`"`

`\(`

`value`

`)`

`\(`

`symbol`

`)`

`"`

`)`

`}`

`[`

`totalDeciliters`

`,`

`totalLiters`

`,`

`totalPints`

`].`

`forEach`

`{`

`showInfo`

`(`

`for`

`:`

`$0`

`)}`

The output printed to the console will be similar to this:

562.633599246894 tsp 187.544025752698 tbsp 11.5549 cup

## See Also

Get *iOS 11 Swift Programming Cookbook* now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.