确定用户"温度单位"设置在iOS 10(摄氏/华氏)

时间:2016-09-27 14:15:27

标签: ios locale ios10

iOS 10增加了用户设置"温度单位"设置>下的选项一般>语言与区域>温度单位。

我的应用程序如何以编程方式确定此设置,以便显示正确的温度单位?我倾注了NSLocale.h,并没有看到任何相关内容。

(在iOS 10之前,测试区域设置是否使用指标并假设用户希望使用Celsius就足够了。这已经不再适用了。)

6 个答案:

答案 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 commentpedrouan'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

注意:它可能不适用于模拟器,它适用于设备