Measurement and Unit — Displaying Human-Friendly Content
#Few updates done on — 7 July 2021 with respect to iOS 15
In WWDC21, Apple has given a new approach to available formatters in iOS 15. Simplified by moving most of the API calling logic under one umbrella, so less API calling for developers.
iOS has a set of many useful formatters that help us present data in the localized format without having to do it ourselves. The previous workflow is that we first instantiate the formatter, configure it, and then use it to format data. This is no longer case in iOS 15. Instead, these formatters are hidden behind a new API that starts with formatted method.
Respective iOS 15 API calling visit ThisDevBrain blog.
What was the need of Measurement class?
The complication every developer continued facing for the past couple of decades is to play with the unit.
How to covert a precise unit into a specific unit?. How to represent it with the correct symbol? Mostly, we solved this with our very own String concatenation.
If value > 1000 {let result = value/1000return “\(result) km” // or miles ???} else {return “\(value) m”}// What about the correct unit will it be km or miles??? Hmm...
We all need to convert one unit to another. We generally, Google what the conversion should be?
However, we can now use some built-in structures to represent and convert your units.
What is system of measurement? Different units adopted by region?
A system of measurement is a collection of units of measurement and rules relating them to each other.
Systems of measurement in use include the International System of Units (SI), the modern form of the metric system, the British imperial system, and the United States customary system.
- Metric system
Multiples and submultiples of metric units are related by powers of ten and their names are formed with prefixes. This relationship is compatible with the decimal system of numbers and it contributes greatly to the convenience of metric units.
The units that serves as the SI base units are the metre, kilogram, second, ampere, kelvin, mole, and candela.
- Imperial and US customary units
Both imperial units and US customary units derive from earlier English units.
Units of length and area (the inch, foot, yard, mile, etc.), fluid ounce (fl oz),
Apple has introduced Unit and Measurement related classes in the Foundation framework.
The following are the classes and structures to help us to deal with it.
- Unit : An abstract class representing a unit of measure.
class Unit : NSObject
The instance of a Unit subclass consists of property calledsymbol
. (The symbolic representation of the unit.) This class defines a symbol for the unit, such as m for meters, km for kilometers, etc.
- Dimension : An abstract class representing a dimensional unit of measure.
class Dimension : Unit
The Foundation framework provides concrete subclasses for many of the most common types of physical units.
Each instance of a Dimension subclass has a converter
, which is used to represent the unit in terms of the dimension’s base unit
.
- Measurement : A numeric quantity labelled with a unit of measure, with support for unit conversion and unit-aware calculations.
struct Measurement<UnitType> where UnitType : Unit
Let’s try to understand the usage with the help of code snippets.
Let’s say you want to measure a length and use it with a different form of the same unit family.
NOTE: You should know the value unit that you might receive from the user, server, or anywhere.
Create a Measurement with a specified value and unit.
let centimeters = Measurement(value: 1000, unit: UnitLength.centimeters) // 1000.0 cm
It will create a Measurement with UnitType
of type Lenght
.
Let view, what this measurement object holds in it?
The value
will be of type Double
and the unit.symbol
of type String
.
However, mostly we want to display the values on the screen. The value & symbol properties are again asking us to take a legacy route we discussed at the beginning of the article. i.e., String concatenation. We were trying to avoid it in the first place. Looks like, we have reached the same place from where we started.
We all know that we need a String type. It needs some formatting. i.e., MeasurementFormatter. A formatter provides localized representations of units and measurements.
MeasurementFormatter has an instance method string that takes the measurement object and returns the readable format measurement.
We were expecting 1000.0 cm and 10.0 m
There are two problems in above result?
Problem 1:
The Unit
type we have got is not matching with the country or region measurement unit system.
For example, In India, it should be Kilometer, In the US, UK it should be in Miles, etc.
Problem 2:
We were expecting the Unit
type in the specific Unit
and not the Unit
chosen by the system by default.
In above its Miles and no feet, pints, and ounces. (Smaller Unit
of miles unit type system)
Solution for Problem 1:
The MeasurementFormatter has a property called locale. Default playground local is en_US, and formatter implicitly converting the measurement object to miles and returns the formatted string as an equivalent measurement in miles.
NOTE: In real project the default locale will be the device locale.
- kilometers may be formatted as “miles” for US and UK locales but “kilometers” for other locales.
Still, the unit is KM and Miles. Not the unit, we applied to create the Measurement object.
Solution for Problem 2:
The MeasurementFormatter has a property called unitOptions, it can be set to ensure that the formatter behaves in a way the developer expects. If not specified, unitOptions defaults to localizing according to the preferences of the locale.
What all unitOptions we have?
- providedUnit: If you set the provided unit in unitOptions then you can format the unit with the required unit type that is cm or m in our current use case.
- naturalScale: Use the natural units to fit the reading into the appropriate unit system based on the value. It automatically shifts to the upper or lower unit based on the unit. Like, instead of saying
1,000m
it will convert it to1 km
. - temperatureWithoutUnit: Specifies that representations of a measurement with the
NSTemperatureUnit
unit omit the letter denoting the temperature scale. For example, a temperature measurement with value equal to 72 using thedegreeFahrenheit()
would be represented as72°
rather than72°F
.
The results are correct, but they are not natural results. For example, As a user, you will not say the destination is 1,000m
. We prefer to say, 1 km
.
You can perform a mathematical operation with ease on the Measurement objects.
Let’s consider the centimeter as the base unit for our length measurement object. The Measurement object allows us to derive the secondary units with ease.
In case you want to convert the Measurement’s UnitType into a specific UnitType. The measurement object has a method call converted, which allows converting the specific unit into any required unit from the same unit family.
One more property the MeasurementFormatter class has which is UnitStyle.
There are 3 type: long, medium, and short.
For example, for English, when formatting “1000 seconds”
* short is 16.667m, medium is 16.667 min, long is 16.667 minutes
- Mass
Let’s play with mass.
- Time
Let’s play with time.
All measurements and units supported by the Foundation framework are as below,
I am pretty sure this article will give you a basic understanding of the measurement and units. You can use your learning easily to evaluate and use other measurements.
Reference:
Sample Code: WWDC 2020 Formatters: Make Data Human Friendly