簡體   English   中英

在 iOS 10(攝氏度/華氏度)上確定用戶的“溫度單位”設置

[英]Determine user's "Temperature Unit" setting on iOS 10 (Celsius / Fahrenheit)

iOS 10 增加了用戶在“設置”>“通用”>“語言和區域”>“溫度單位”下設置“溫度單位”選項的功能。

我的應用程序如何以編程方式確定此設置,以便它可以顯示正確的溫度單位? 我翻遍了 NSLocale.h 並沒有看到任何相關的內容。

(在 iOS 10 之前,測試語言環境是否使用度量並假設度量用戶想要使用攝氏度就足夠了。現在不再如此。)

有一個(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


隨意糾正語法。

我找到了 Alexandre Colucci 的這篇文章: 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) {
    ...
}

它將返回一個字符串,它要么是“Celcius”,要么是“Fahrenheit”。

但是有一個問題:它不向后兼容 10 之前的 iOS 版本。如果您在 iOS 9 或更早版本的設備上運行您的應用程序,您將在應用程序啟動期間收到錯誤“dyld: Symbol not found: _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 拒絕了該應用程序。 所以他們絕對不希望我們使用我們自己的格式化程序類的設置。 我覺得這很煩人。

正確答案來自Fabiopedrouan's answer 的評論,其中引用了 Apple 在論壇上的回復: https : //forums.developer.apple.com/thread/70258

模擬器不遵守溫度單位設置,但真實設備確實遵守該設置。 在模擬器中使用MeasurementFormatter將始終使用區域設置的默認單位,但在真實設備上使用MeasurementFormatter將使用用戶選擇的溫度單位。

這似乎是一個遲到的答案,但我在這里的評論中找到了@fábio-oliveira 提到的一個巧妙的解決方案。

蘋果原帖: https : //forums.developer.apple.com/thread/70258

我在我的解決方案中嘗試做的是有一個函數將開爾文溫度(從 JSON 文件解析,可以是任何溫度)轉換為由系統區域設置或由用戶在設置 > 常規 > 語言設置的溫度格式區域 > 溫度單位 但是,我還需要溫度在小數點分隔符后顯示 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)

讓我知道此解決方案是否適合您,但它確實適合我。 謝謝!

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

同樣,請記住使用實際設備而不是模擬器進行測試。

正如其他人提到的,如果您需要知道當前單位,安全的方法是直接使用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

注意:它可能不適用於模擬器,它適用於設備

我最終做了一些類似於 Amir 但更健壯的事情,即 Amir 的解決方案有時對我來說失敗了。

我沒有通過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
    }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM