iOS 10增加了用户设置"温度单位"设置>下的选项一般>语言与区域>温度单位。
我的应用程序如何以编程方式确定此设置,以便显示正确的温度单位?我倾注了NSLocale.h,并没有看到任何相关内容。
(在iOS 10之前,测试区域设置是否使用指标并假设用户希望使用Celsius就足够了。这已经不再适用了。)
答案 0 :(得分:11)
有一个 (NS)MeasurementFormatter
类。它继承自(NS)Formatter
类。这是适用于iOS 10+ SDK的新课程。
我不确定是否有必要知道用户在他们的偏好中设置了什么单位。
使用 Swift 3 设置 Measurement
:
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
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
系统知道我们设置了什么单位。它将处理所有值转换工作,因为该值设置为值和测量单位。
手动转换:
measurement.converted(to: UnitTemperature.kelvin).value // 297.65
斯威夫特:
https://developer.apple.com/reference/foundation/measurementformatter
目标C:
https://developer.apple.com/reference/foundation/nsmeasurementformatter?language=objc
随意更正语法。
答案 1 :(得分:5)
Alexandre Colucci撰写的这篇文章发现:http://blog.timac.org/?tag=nslocaletemperatureunit
首先,公开NSLocaleTemperatureUnit NSLocaleKey:
FOUNDATION_EXPORT NSLocaleKey const NSLocaleTemperatureUnit;
然后检查单位:
temperatureUnit = [[NSLocale currentLocale] objectForKey:NSLocaleTemperatureUnit]
或Swift(2.3):
if let temperatureUnit = NSLocale.currentLocale().objectForKey(NSLocaleTemperatureUnit) {
...
}
它将返回一个“Celcius”或“Fahrenheit”的字符串。
但是存在一个问题:它不能向后兼容早于10的iOS版本。如果您在iOS 9或更早版本的设备上运行您的应用,您将在应用期间收到错误“dyld:未找到符号:_NSLocaleTemperatureUnit”启动。
解决方案是对NSLocaleTemperatureUnit变量定义使用弱链接。像这样:
FOUNDATION_EXPORT NSLocaleKey const NSLocaleTemperatureUnit __attribute__((weak_import));
这将让应用程序通过dyld检查。但现在您必须在使用NSLocaleTemperatureUnit之前检查操作系统版本,否则您的应用程序将因异常而崩溃。
if #available(iOS 10,*) {
if let temperatureUnit = NSLocale.currentLocale().objectForKey(NSLocaleTemperatureUnit) {
...
}
}
编辑:
我在我的应用程序中尝试过,但是当我将它上传到Testflight时Apple拒绝了该应用程序。所以他们绝对不希望我们将这个设置用于我们自己的格式化程序类。我发现这很烦人。
答案 2 :(得分:1)
这似乎是一个迟到的答案,但我在这里的评论中找到了@fábio-oliveira提到的一个简洁的解决方案。
最初的Apple主题:https://forums.developer.apple.com/thread/70258
我在我的解决方案中尝试做的是将函数转换为开尔文温度(从JSON文件解析并可以是任何温度)到由 Systems Locale 或由用户在设置>中设置一般> Langauge&区域>温度单位。但是,我还需要温度在小数分隔符后显示0位数。
所以这是一个 Swift 4 解决方案(开尔文是输入温度单位):
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/tri_logo"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:src="@drawable/tri_logo"/>
</RelativeLayout>
在这里你可以 调用你的函数 来转换值( _currentTemp 是你提取的JSON温度值&amp; convertedTemp < / em>是根据上述条件得到的转换温度):
func temperatureFormatter(kelvinTemp: Double) -> String{
let mf = MeasurementFormatter()
mf.numberFormatter.maximumFractionDigits = 0
let t = Measurement(value: kelvinTemp, unit: UnitTemperature.kelvin)
return (String(format:"%@", mf.string(from: t)))
}
让我知道这个解决方案是否适合您,但它对我有用。谢谢!
答案 3 :(得分:1)
我为UnitTemperature
写了一个扩展名,以根据Fábio Oliveira的发现来选择单位。我的用例是知道用户选择了哪个单位,而不必使用它来显示某些东西,这就是我的方法。
extension UnitTemperature {
static var current: UnitTemperature {
let measureFormatter = MeasurementFormatter()
let measurement = Measurement(value: 0, unit: UnitTemperature.celsius)
let output = measureFormatter.string(from: measurement)
return output == "0°C" ? .celsius : .fahrenheit
}
}
同样,请记住使用实际设备而不是模拟器进行测试。
答案 4 :(得分:0)
正确的答案是从Fabio's comment到pedrouan's answer,它引用了Apple在以下论坛上的回应:https://forums.developer.apple.com/thread/70258。
模拟器不遵守温度单位设置,但实际设备确实遵守该设置。在模拟器中使用MeasurementFormatter
将始终使用语言环境的默认单位,但在真实设备上使用MeasurementFormatter
将使用用户选择的温度单位。
答案 5 :(得分:0)
正如其他人提到的,如果您需要知道当前单位,安全的方法是直接使用 MeasurementFormatter
进行格式化!我制作了这个扩展,它适用于 Swift 5 和更新版本:
extension UnitTemperature {
static var current: Self {
let formatter = MeasurementFormatter()
formatter.locale = .init(identifier: "en_US")
formatter.unitStyle = .long
let formatted = formatter.string(from: .init(value: 0, unit: Self.celsius))
return Self(symbol: formatted.components(separatedBy: " ").last!)
}
}
你可以像这样使用它:
UnitTemperature.current
注意:它可能不适用于模拟器,它适用于设备