Setting locale on MeasurementFormatter voids settings of numberFormatter property

Originator:beshbashbosh
Number:rdar://48920090 Date Originated:15-Mar-2019
Status:Open Resolved:
Product:iOS+SDK Product Version:iOS 10+
Classification:Other Bug Reproducible:Always
 
Area:
Foundation

Summary:
Changing the locale on a MeasurementFormatter voids numberFormatter settings. 
One would expect to be able to change the format of the numbers even after settings a locale on the formatter. Whether or not this is intended behaviour is not documented anywhere or reported on popular development forums (e.g. StackOverflow, although I will put something there to notify others).

Steps to Reproduce:
1. Run this:

```
import Foundation
let formatter = MeasurementFormatter()
formatter.numberFormatter.minimumFractionDigits = 4
formatter.numberFormatter.maximumFractionDigits = 4
let distanceInKm = 16.093 // ~10 mi
var measurement: Measurement<UnitLength> = Measurement(value: distanceInKm, unit: .kilometers)
let string = formatter.string(from: measurement) // 9.998 mi
assert(string == "9.9998 mi")
```

2. Now add a locale to the MeasurementFormatter instance and create a string from the same distance

```
formatter.locale = Locale(identifier: "en_GB") // Set the locale
let string2 = formatter.string(from: measurement) // 10 mi
assert(string2 == "9.9998 mi") // No longer formatted to 4 fractional digits
```

Expected Results:
Changing the locale on MeasurementFormatter should retain the options set in the associated numberFormatter property. If there is a reason this doesn't work, it should be documented to save developers time trying to get it to work.

Actual Results:
Setting a locale on the MeasurementFormatter voids any options set in the numberFormatter property.

Version:
iOS 10.0+

Notes:
Swift 4.2

Setting the numberFormatter properties again after setting a locale to the MeasurementFormatter instance does not re-enable functionality. e.g.

```
formatter.locale = Locale(identifier: "en_GB") // Set the locale
formatter.numberFormatter.minimumFractionDigits = 4 // set numberFormatter properties again
formatter.numberFormatter.maximumFractionDigits = 4
let string3 = formatter.string(from: measurement) // still 10 mi
assert(string3 == "9.9998 mi") // Still not formatted as per numberFormatter options
```

Comments

Its because setting the locale nulls the numberFormatter, see setNumberFormatter:0x0 below from Hopper:

/* @class NSUnitFormatter */
-(void)setLocale:(void *)arg2 {
rbx = arg2;
r14 = self;
if (arg2 == 0x0) {
        rbx = [NSLocale currentLocale];
}
r12 = *ivar_offset(_locale);
if ([*(r14 + r12) isEqual:rbx] == 0x0) {
        r15 = *(r14 + r12);
        *(r14 + r12) = [rbx retain];
        [r15 release];
        [r14 setNumberFormatter:0x0];
        *(int8_t *)&r14->_modified = 0x1;
}
return;
}

Internally, NSMeasurementFormatter is a wrapper of NSUnitFormatter.

And FYI if you change the temperature format in settings, that nulls the number formatter too on the next call to formatter.string(from:

By indiekiduk at Oct. 21, 2020, 12:24 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!