iOS 10 Temperature Unit

Hi. iOS 10 has a new setting 'Temperature Unit'. Users can choose a temperature unit, independent of their Locale/Region.


I had found this blog post, which explained how to get it's value: http://blog.timac.org/?tag=nslocaletemperatureunit. And it works great. I modified it a little bit so that it would be backwards compatible from iOS8 up to iOS10.


However... When I submitted my app to Testflight, the app was rejected for the reason: "The app references non-public symbols in [app-name]: _NSLocaleTemperatureUnit"


That's rather disappointing, because I know of no other way to find out what the user entered for this setting. I am 100% sure that users WILL change this setting, and then be disappointed that my app only looks at the region to determine if Celcius or Fahenrheit should be used.


Is there any official solution for this predicament?


Please check here what I did: http://stackoverflow.com/questions/39727075/determine-users-temperature-unit-setting-on-ios-10-celsius-fahrenheit

Replies

Are you just trying to render a temperature with the user’s preferred units? If so, take a look at NSMeasurementFormatter. For example, this code:

let mf = MeasurementFormatter()
let t = Measurement(value: 0, unit: UnitTemperature.celsius)

NSLog("%@", mf.string(from: t))

prints:

  • Fahrenheit by default in the US locale

  • Celcius by default in the UK locale

  • Fahrenheit in the UK locale if the user has explicitly overridden it via Settings > General > Langauge & Region > Temperature Unit.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
  • I need to display different labels on axes of temperature charts based on user's temperature unit. How do I know the user's temperature unit? Why does iOS allow temperature unit independent of the metric/standard unit system?

Add a Comment

I tried this code, using Xcode 8.1, with simulator iPhone 7, iOS 10.1:


    NSMeasurementFormatter* mf = [[NSMeasurementFormatter alloc] init];
    NSMeasurement* t = [[NSMeasurement alloc] initWithDoubleValue:37.0 unit:[NSUnitTemperature celsius]];
    NSLog(@"%@", [mf stringFromMeasurement:t]);

It prints:

  • Region: Netherlands, Temperature Unit: Celcius

    37°C

  • Regoin: Netherlands, Temperature Unit: Fahrenheit

    37°C

  • Region: United States, Temperature Unit: Celcius

    98.6°F

  • Region: United States, Temperature Unit: Fahrenheit

    98.6°F


And just for good measure ("Fahrenheit in the UK locale if the user has explicitly overridden it via Settings > General > Langauge & Region > Temperature Unit."):


Region: United Kingdom, Temperature Unit: Fahrenheit

  • 37°C


Just try it... The Temperature Unit is completely disregarded.


EDIT:


Tried it with Xcode 8.2 and iOS 10.2 simulator. No dice.

I tried this code, using Xcode 8.1, with simulator iPhone 7, iOS 10.1:

Tried it with Xcode 8.2 and iOS 10.2 simulator. No dice.

Please try on a real device.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Maybe just use the actual sting value of _NSLocaleTemperatureUnit, rather than importing the constant? At least that would circumvent it flagging as use of a private symbol... Not sure of thats ok in the *spirit* of the rule, but yoiu'd adhere to the letter of of, at least 😉

Maybe just use the actual sting value of _NSLocaleTemperatureUnit, rather than importing the constant?

This is very bad advice. Using private APIs is not just a potential App Review pitfall, it also exposes you to compatibility problems down the track. You really don’t want to go there, especially when there’s a supported solution that works well AFAICT (but perhaps not so well on the simulator).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

The function is a nice idea but the functionality is buggy. Please fix it in iOS 11

https://openradar.appspot.com/radar?id=5042283099455488

Why does iOS allow temperature unit independent of the metric/standard unit system?

Because… well… people. Unit choice can be very personal and it can also be very context specific. For example:

  • Growing up in Australia I’m fully committed to metric, but I still have Maps configured to use miles because that matches all the road signs here in the UK.

  • The US is the most Imperial of Imperial countries, right? Recently I’ve been reading up on 1940s era aircraft engines and it seems that US aeroplanes of that era used Celcius to measure engineer temperatures. Why? No idea!

How do I know the user's temperature unit?

AFAIK there’s no API to return the value set by the user in Settings > General > Langauge & Region > Temperature Unit. That’s obviously annoying and I recommend that you file an enhancement request for such an API. Please post your bug number, just for the record.

As to what you should do right now, that depends on the context. You wrote:

I need to display different labels on axes of temperature charts based on user's temperature unit.

My advice:

  • If there’s a unit that’s typically used for this context — for example, Celcius for engine temperatures — default to that.

  • If not, set your default based on usesMetricSystem.

  • Provide a UI to override that default.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • Enhancement request FB9649823. Thanks.

Add a Comment

My use case for wanting to know what unit a user has selected is to be able to display a toggle that defaults to their selected unit.

I found a hacky way to do this on iOS, but sadly not on macOS.

let temp = Measurement(value: 9, unit: UnitTemperature.celsius)
let formattedTemp = temp.formatted(.measurement(width: .abbreviated, usage: .person, numberFormatStyle: .number))
let unit = formattedTemp.firstIndex(of: "F") != nil ? UnitTemperature.fahrenheit : UnitTemperature.celsius

This code relies on the usage: .person part that seems to format according to what temperature unit the user has selected.

@yvsong Did you ever get a response on your enhancement request?