/MKUnits

Unit conversion library for Objective-C.

Primary LanguageObjective-CMIT LicenseMIT

MKUnits

Twitter License CocoaPods Build Status

MKUnits is extremely precise unit conversion library for Objective-C. It provides units of measurement of physical quantities and simplifies manipulation of them.

License

Source code of this project is available under the standard MIT license. Please see the license file.

Example

Let's create 1.5 kilograms [kg],

id kilograms = [@1.5 mass_kilogram];

0.5 [kg] in grams [g]

id grams = [@500 mass_gram];

and 10 pounds [lb] (which is 4.5359237 [kg])

id pounds = [@10 mass_pound];

Then we add all of the above togehter and subtract 0.0001 [kg] in milligrams [mg].

id milligrams = [@100 mass_milligram];
id result = [[[kilograms add:grams] add:pounds] subtract:milligrams];

The result amount is 6.5358237 [kg].

Now we subtract 0.5358237 [kg] in ounces [oz], which is 18.900624805 [oz] according to Google converter, but as MKUnits is very precise, it is in fact 18.900624805483390296005199558361177 [oz].

id ounces = [[@0.5358237 mass_kilogram] convertTo:[MKMassUnit ounce]];
result = [result subtract:ounces];

The result amount is ~6 [kg]; 6.00000000000000000000000000000000003 [kg] to be exact.

Now we want the result to be in stones [st], so:

result = [result convertTo:[MKMassUnit stone]];
// 0.94483873964811055873038869091017890993 st

As the result is too precise for our needs, we want to round it.

We can do that by either creating new MKQuantity object with rounded amount,

id stone_quantity = [result quantityWithPrecision:3];
// 0.945 st

or by rounding the amount of existing MKQuantity.

id amount_in_stones_1 = [result amountWithPrecision:3];
// 0.945

id amount_in_stones_2 = [[result amount] mk_roundedWithPrecision:3];;
// 0.945

Supported Quantities

At the moment MKUnits supports the following quantities:

  • Area (base unit: square meter)
  • Bytes (base unit: bit)
  • Mass (base unit: kilogram)
  • Length (base unit: meter)
  • Time (base unit: second)

You can easily extend MKUnits by adding new quantities or units.

Quick Conversion

MKUnits supports quick number conversion between different units without the need of instantiating MKQuantity objects.

Converting amount of 1 [kg] to 1000 [g] can be achieved in the following ways:

id amount = [MKUnit convertAmount:@1 from:[MKMassUnit kilogram] to:[MKMassUnit gram]];

id amount = [[MKMassUnit kilogram] convertAmount:@1 to:[MKMassUnit gram]];

id amount = [[MKMassUnit gram] convertAmount:@1 from:[MKMassUnit kilogram]];

Precision and Rounding

MKUnits uses NSDecimalNumber for all operations, therefore, it is extremely precise.

To round a number to a desired decimal place, simply use mk_roundedWithPrecision: method of NSNumber+MK_Precision category.

Example: Rounding 1.123456789 to 5 decimal places:

[@1.123456789 mk_roundedWithPrecision:5]; // results in 1.12346.

Alternatively you can take advantage of MKQuantity+Precision category which offers the following methods:

- (instancetype)quantityWithPrecision:(short)precision;
- (NSNumber *)amountWithPrecision:(short)precision;

- (BOOL)isTheSame:(MKQuantity *)other withPrecision:(short)precision;
- (BOOL)isGreaterThan:(MKQuantity *)other withPrecision:(short)precision;
- (BOOL)isLessThan:(MKQuantity *)other withPrecision:(short)precision;

- (NSComparisonResult)compare:(MKQuantity *)other withPrecision:(short)precision;

Extending MKUnits

Adding new Quantity

In order to add new Quantity simply create a class that extends MKUnit and follow the convention below.

Please make sure that unit symbols are unique across your Quantity.

Example .h file:

@interface QuantityUnit : MKUnit

+ (instancetype)unit_one;
+ (instancetype)unit_two;

@end

@interface MKQuantity (QuantityUnit)

+ (instancetype)quantity_unitoneWithAmount:(NSNumber *)amount;
+ (instancetype)quantity_unittwoWithAmount:(NSNumber *)amount;

@end

@interface NSNumber (QuantityUnit)

- (MKQuantity *)quantity_unitone;
- (MKQuantity *)quantity_unittwo;

@end

Example .m file:

@implementation QuantityUnit : MKUnit

+ (instancetype)unit_one {
    static NSString *name   = @"unit_one";
    static NSString *symbol = @"u1";
    id ratio = [NSDecimalNumber one]; // as it is a base unit
    
    return [self createWithName:name
                     withSymbol:symbol
                      withRatio:ratio];
}

+ (instancetype)unit_two {
    static NSString *name   = @"unit_two";
    static NSString *symbol = @"u2";
    id ratio = [NSDecimalNumber decimalNumberWithMantissa:2 exponent:0 isNegative:NO];
    
    return [self createWithName:name
                     withSymbol:symbol
                      withRatio:ratio];
}

@end

@implementation MKQuantity (QuantityUnit)

+ (instancetype)quantity_unitoneWithAmount:(NSNumber *)amount {
	return [self createWithAmount:amount withUnit:[QuantityUnit unit_one]];
}

+ (instancetype)quantity_unittwoWithAmount:(NSNumber *)amount {
	return [self createWithAmount:amount withUnit:[QuantityUnit unit_two]];
}

@end

@implementation NSNumber (QuantityUnit)

- (MKQuantity *)quantity_unitone {
	return [MKQuantity quantity_unitoneWithAmount:self];
}

- (MKQuantity *)quantity_unittwo {
	return [MKQuantity quantity_unittwoWithAmount:self];
}

@end

Adding new Unit to existing Quantity

To add additional units to existing Quantity simply create a category for that Quantity.

Do not sublcass as units are only interconvertible with units belonging to the same Quantity.

Example .h file:

@interface GroupUnit (Extension)

+ (instancetype)unit_one;
+ (instancetype)unit_two;

@end

@interface MKQuantity (GroupUnit_Extension)

+ (instancetype)group_unitoneWithAmount:(NSNumber *)amount;
+ (instancetype)group_unittwoWithAmount:(NSNumber *)amount;

@end

@interface NSNumber (GroupUnit_Extension)

- (MKQuantity *)quantity_unitone;
- (MKQuantity *)quantity_unittwo;

@end