Determine user's "Temperature Unit" setting on iOS 10 (Celsius / Fahrenheit)
There is an (NS)MeasurementFormatter
class. It inherits from an (NS)Formatter
class. It's a new class available for iOS 10+ SDK.
I am not sure whether it's necessary to know, what unit a user has set in their preferences.
To set a Measurement
using Swift 3:
let formatter = MeasurementFormatter()
let measurement = Measurement(value: 24.5, unit: UnitTemperature.celsius)
let temperature = formatter.string(from: measurement)
print(temperature) // 76.1°F
// this value was computed to Fahrenheit value on my locale/preferences
For retrieval of a Measurement
:
print(measurement.unit) // °C - always celsius as it was set as Celsius
formatter.unitStyle = .long
formatter.locale = Locale.current
formatter.string(from: measurement.unit) // degrees Celsius - always an original unit
formatter.string(from: measurement) // 76.1 degrees Fahrenheit - regarding locale/settings
formatter.locale = Locale.init(identifier: "it_IT")
formatter.string(from: measurement.unit) // gradi Celsius - always an original unit
formatter.string(from: measurement) // 24,5 gradi Celsius - regarding locale/settings
The system knows, what unit we have set. It will handle all the value conversion work, because the value was set as a pair of a value and a measurement unit.
For manual conversion:
measurement.converted(to: UnitTemperature.kelvin).value // 297.65
Swift:
https://developer.apple.com/reference/foundation/measurementformatter
Objective-C:
https://developer.apple.com/reference/foundation/nsmeasurementformatter?language=objc
Feel free to correct a grammar.
There is this article by Alexandre Colucci that I found: http://blog.timac.org/?tag=nslocaletemperatureunit
First, expose the NSLocaleTemperatureUnit NSLocaleKey:
FOUNDATION_EXPORT NSLocaleKey const NSLocaleTemperatureUnit;
Then check the unit with this:
temperatureUnit = [[NSLocale currentLocale] objectForKey:NSLocaleTemperatureUnit]
Or Swift (2.3):
if let temperatureUnit = NSLocale.currentLocale().objectForKey(NSLocaleTemperatureUnit) {
...
}
It will return a string which is either "Celcius" or "Fahrenheit".
But there is an issue: it's not backwards compatible with iOS versions earlier than 10. If you run your app on an iOS 9 or earlier device, you'll get an error "dyld: Symbol not found: _NSLocaleTemperatureUnit" during app startup.
The solution is to use weak linking for the NSLocaleTemperatureUnit variable definition. Like this:
FOUNDATION_EXPORT NSLocaleKey const NSLocaleTemperatureUnit __attribute__((weak_import));
This will let the app pass the dyld checks. But now you will have to check for the OS version before using NSLocaleTemperatureUnit, or your app will crash with an exception.
if #available(iOS 10,*) {
if let temperatureUnit = NSLocale.currentLocale().objectForKey(NSLocaleTemperatureUnit) {
...
}
}
EDIT:
I tried it in my app, but Apple rejected the app for it when I uploaded it to Testflight. So they definitely don't want us to use the setting for our own formatter classes. I find that pretty annoying.
The correct answer is from Fabio's comment to pedrouan's answer, which references Apple's response on the forums: https://forums.developer.apple.com/thread/70258.
The Simulator does not respect the Temperature Unit setting, but real devices do respect that setting. Using MeasurementFormatter
in the Simulator will always use the locale's default unit, but using MeasurementFormatter
on a real device will use the user's selected Temperature Unit.