确定用户在iOS 10上的“温度单位”设置(摄氏度/华氏度)

fdx2calv  于 2022-12-15  发布在  iOS
关注(0)|答案(8)|浏览(131)

iOS 10增加了用户在设置〉通用〉语言和地区〉温度单位下设置其“温度单位”选项的功能。
我的应用如何以编程方式确定此设置,以便显示正确的温度单位?我浏览了NSLocale.h,没有看到任何相关内容。
(在iOS 10之前,只需测试区域设置是否使用公制,并假设公制用户希望使用摄氏度即可。现在不再是这种情况。

bmvo0sr5

bmvo0sr51#

有一个**(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
随意纠正语法。

ui7jx7zq

ui7jx7zq2#

我找到了 Alexandria ·科卢奇的这篇文章:http://blog.timac.org/?tag=nslocaletemperatureunit
首先,公开NSLocaleTemperatureUnit NSLocaleKey:

FOUNDATION_EXPORT NSLocaleKey const NSLocaleTemperatureUnit;

然后用这个检查装置:

temperatureUnit = [[NSLocale currentLocale] objectForKey:NSLocaleTemperatureUnit]

或者斯威夫特(2.3):

if let temperatureUnit = NSLocale.currentLocale().objectForKey(NSLocaleTemperatureUnit) {
    ...
}

它将返回一个字符串,该字符串不是“摄氏度”就是“华氏度”。
但有一个问题:不向后兼容iOS 10之前的版本。如果您在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时,苹果拒绝了这个应用程序。所以他们肯定不希望我们使用我们自己的格式化程序类的设置。我觉得这很烦人。

hjzp0vay

hjzp0vay3#

我为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
  }
}

再次提醒,请记住使用实际设备而不是模拟器来测试。

lnlaulya

lnlaulya4#

正确答案来自Fabio对pedrouan's answer的评论,其中引用了苹果在论坛上的回应:https://forums.developer.apple.com/thread/70258 .
模拟器不考虑温度单位设置,但真实的设备 * 会 * 考虑该设置。在模拟器中使用MeasurementFormatter将始终使用区域设置的默认单位,但在真实设备上使用MeasurementFormatter将使用用户选择的温度单位。

zpf6vheq

zpf6vheq5#

这似乎是一个迟来的答案,但我发现了@fábio-oliveira在这里的评论中提到的一个简洁的解决方案。
原始Apple线程:https://forums.developer.apple.com/thread/70258
我在解决方案中尝试做的是提供一个函数,将开尔文温度(从JSON文件解析,可以是任何温度)转换为*系统区域设置*指定的温度格式,或者由用户在 Settings〉General〉Langauge & Region〉Temperature Unit 中设置。但是,我还需要温度在小数点后显示0位数。
下面是
Swift 4
解决方案(开尔文是输入温度单位):

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)))
    }

在这里,您可以**调用函数**来转换值(_currentTemp 是提取的JSON温度值,convertedTemp 是基于上述条件转换的结果温度):

convertedTemp = temperatureFormatter(kelvinTemp: _currentTemp)

让我知道如果这个解决方案对你有效,它确实对我有效。谢谢!

6ljaweal

6ljaweal6#

正如其他人提到的,安全的方法是直接使用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

**注:**可能无法在模拟器上运行,但可在设备上运行

xqkwcwgp

xqkwcwgp7#

我最终做了一些类似于阿米尔,但更强大一点,即阿米尔的解决方案是失败的,我有时。
我没有通过Self(symbol:)进行示例化,而是根据三个选项匹配格式化时返回的符号:

extension UnitTemperature {
  static var current: UnitTemperature {
    let formatter = MeasurementFormatter()
    formatter.locale = Locale.autoupdatingCurrent
    formatter.unitStyle = .medium
    let formatted = formatter.string(from: .init(value: 0, unit: UnitTemperature.celsius))
    let symbol = String(formatted.suffix(2))
    switch (symbol) {
      case UnitTemperature.celsius.symbol:
        return .celsius
      case UnitTemperature.fahrenheit.symbol:
        return .fahrenheit
      default:
        return .kelvin
    }
  }
}
hfsqlsce

hfsqlsce8#

只需将系统区域设置字符串与已知字符串进行比较。如下所示:

static public func getDefaultTemperatureUnits() -> UserPreferences.TemperatureUnits {
    let locale = Locale.current
    let formatter = MeasurementFormatter()
    let measurement = Measurement(value: 37.0, unit: UnitTemperature.celsius)
    formatter.unitStyle = .medium

    formatter.locale = Locale.current
    let localeTemperature = formatter.string(from: measurement).lowercased()
    
    let formatter2 = MeasurementFormatter()
    let numberFormatter = NumberFormatter()
    numberFormatter.maximumFractionDigits = 0
    formatter2.numberFormatter = numberFormatter
    formatter2.unitOptions = [.providedUnit]
    formatter2.unitStyle = .medium
    let temperature = formatter2.string(from: measurement.converted(to: UnitTemperature.celsius))
    let knownCelsiusTemperature = temperature.lowercased()
    
    return knownCelsiusTemperature == localeTemperature ? .celsius : .fahrenheit
}

这对所有语言都有好处。

相关问题