Reda Lemeden

Reda Lemeden

Indie Developer & Designer

Units in Foundation


Starting iOS 10 and macOS 10.12, Foundation supports units and measurements out of the box, in the form of (NS)Unit and (NS)Measurement respectively. Let’s take a look at how they work.

Note: All code snippets below are written in Swift 3.0.

To get started, let’s define a measurement. To do that, you have to pass a value and a unit to the initializer:

import Foundation

let snorlaxWeight = Measurement(value: 460, unit: UnitMass.kilograms)
// -> 460.0 kg

You can then effortlessly convert the measurement to another unit:

let snorlaxWightInImperial = snorlaxWeight.converted(to: .pounds)
// -> 1014.12723328454 lb

You can also define your own unit by extending one of the default dimensions available:

extension UnitMass {
  static let snorlax = UnitMass(symbol: "snorlax", converter: UnitConverterLinear(coefficient: 460))
}

The converter is used to transform the measurement from any given unit to the base unit of the dimension; Kilograms in the case of UnitMass. You can inspect the base unit of any dimension by calling baseUnit() on it.

UnitMass.baseUnit()
// -> kg

Once defined, your custom unit can be used alongside the pre-defined ones:

let statueOfLibertyMass = Measurement(value: 225_000, unit: UnitMass.kilograms)
let statueOfLibertyMassInSnorlax = statueOfLibertyMass.converted(to: .snorlax)
// -> 489.130434782609 snorlax

You can also define a custom dimension of units by subclassing Dimension if necessary. Here is an example that defines a new UnitDataRate class for measuring data transfer rates, often used in Internet speed tests:

class UnitDataRate: Dimension {
  static let kilobitPerSecond = UnitDataRate(symbol: "kbps", converter: UnitConverterLinear(coefficient: 1))
  static let megabitPerSecond = UnitDataRate(symbol: "Mbps", converter: UnitConverterLinear(coefficient: 1_000))
  static let gigabitPerSecond = UnitDataRate(symbol: "Gbps", converter: UnitConverterLinear(coefficient: 1_000_000))

  override class func baseUnit() -> UnitDataRate {
    return .megabitPerSecond
  }
}

let speed = Measurement(value: 100, unit: UnitDataRate.megabitPerSecond)
let speedInKpbs = speed.converted(to: .kilobitPerSecond)

// -> 100000 kbps

Learn More