[iOS 10 day by day] Day 7:Measurement

在iPhone7發布之后,令人興奮的事情已經塵埃落定,現在是時候繼續看看iOS10提供的新特性
這一周我們將要看看新的Measurement API:the Foundation framework的新部分。從表面上看,它看起來并不是都那么興奮:它提供了一種在計量單位間轉化的方式就像公里和英里。

然而,當你仔細思考它,我們花費了極多的時間去轉化值。這可能發生在由于你有角度,但是你所用來旋轉視圖所用的API要求用弧度。可選擇的,可能因為你的應用用英里計算距離,但是你需要為了那些更喜歡用公里單位的用戶去轉換成公里單位。
在iOS10之前,你可能有創造自己的函數去轉換值乘其它的單位或者用外部庫?,F在蘋果已經為你提供了有很大操控提升的API,所以讓我們看看它到底能做什么。

基礎 The Basics
This post uses Swift 3 released as part of the Xcode 8 GM build.
我們用測量模型去創造我們的量度用特殊的維度。你可以把“dimension”當作一個有關聯并且可以相互轉換的單位組,比如克可以轉變成千克或者也能再次返回。每一個dimension有它自己的基礎單位,而其它的單位就有了其相反的定義。像容積的基本單位是公升,一毫升被定義為0.001公升。

Creating Our Measurement
簡單的開始,假設我有一品脫的牛奶而且想知道它有多少毫升,像這樣:

let milk = Measurement(value: 1, unit: UnitVolume.imperialPints)
milk.converted(to: .liters)
// prints out 0.568261 L

這是很簡單的。一旦我們憑借單位dimension定義了我們的量度,我們可以
合適的轉換成dimension的其它單位。我們自動檢查獲取milk變量的類型是Measurement<UnitVolume>。它做了完美的表現,令我們可以合適的在這個組中轉換成其它的值。畢竟,我們如何才能轉換一公升的水成一公里。

Operators
Measurement API 支持運算符操作使用。
如果我們現在想要5品脫的牛奶,我們可以這樣做

let fivePints = milk * 5

這個返回了新的量度,因此我們可以依次轉換成其它的單位。

fivePints.converted(to: .cups)
// Prints 11.8387708333333 cup

你可以注意到當我們在playground使用,或者打印出Measurement,我們獲取了附加的單位符號。
當然,乘法不是我們僅可用的操作符。其它的,我們有相等:

let kms = Measurement(value: 5, unit: UnitLength.kilometers)
let meters = Measurement(value: 5000, unit: UnitLength.meters)
kms == meters // true

和加法:

kms + meters // 10000.0 m
Formatters

早先我提到的我們可能想去展現不同的單位在不同的地方。
伴隨著新的Measurement API,蘋果也提供了MeasurementFormatter,一個添加了個在轉化成字符串之前格式化量度的能力。

默認的,the measurement formatter將會使用用戶當前的區域。我們將會手動的改變去看看當我們想去輸出在兩個城市間的距離時發生什么:

let newcastleToLondon = Measurement(value: 248, unit:     UnitLength.miles)

let formatter = MeasurementFormatter()
formatter.locale = Locale(identifier: "fr")
formatter.string(from: newcastleToLondon) // Prints 399,166 km

formatter.locale = Locale(identifier: "en_GB")
formatter.string(from: newcastleToLondon) // Prints 248 mi

好的!我們解決所有這些但是幾乎不需要我們自己做任何工作。

Project
我們已經快速看了這個API的基礎用法,因此讓我們對它做點有意思的事情。
我們將會創造一個風力渦輪,伴隨著與能被滑塊所調校的風速相比例旋轉的刀片。
這個渦輪相當于一個uiview的子類。它被添加到UIViewControllerview上,并伴隨著其它的基礎UI元素:這個滑塊調整風速而且label將會用米每秒(m/s)和英里每小時(mph)來輸出風速。如果你想在playground中完整的查看,請到github上自由瀏覽。
我們將會集中在使用Measurement API的部分上:開始時,當滑塊的值改變時展現風速在label上:

 func handleWindSpeedChange(slider: UISlider) {
 let windSpeed = Measurement(value: Double(slider.value), unit: UnitSpeed.metersPerSecond)

 let milesPerHour = windSpeed.converted(to: .milesPerHour)

 windSpeedLabel.text = "Wind speed: \(windSpeed) (\(milesPerHour))"

}
我們的label就像下面這樣

未轉化的label.png

哇哦!我們不需要這么精確,對于我們簡單的demo來說。有時我們展現了太多的小數以至于我們不能看見我們按照英里每小時的值。我們可以解決這個依靠我們先前簡要提到的MeasurementFormatter。

let windSpeed = Measurement(value: Double(slider.value), unit:   UnitSpeed.metersPerSecond)

let measurementFormatter: MeasurementFormatter = {
let formatter = MeasurementFormatter()
formatter.unitOptions = .providedUnit
let numberFormatter = NumberFormatter()
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 1
numberFormatter.maximumFractionDigits = 1
formatter.numberFormatter = numberFormatter

return formatter
}()

let metersPerSecond = measurementFormatter.string(from: windSpeed)
let milesPerHour = measurementFormatter.string(from:        windSpeed.converted(to: .milesPerHour))

windSpeedLabel.text = "Wind speed: \(metersPerSecond) (\(milesPerHour))"

我們創建我們的formatter并且要求它使用特定的unitProvided。這個防止the formatter忽略我們所期望的單位并且輸出測試項目接受器tit (test item taker) 覺得最合適的值。對于我,若沒有設置這個值,這個測試項目接受器tit (test item taker) 將會導致我們的量度都按照英里每小時輸出。
The measurement formatter它自己包含了其它能夠允許我們去格式化數值部分的量度的formatter(feels a bit like formatter-ception!)。我們要求這個數字僅展現一個小數。
最后,我們需要去用formatter 去取出string構成我們的m/s和英里每小時量度。

轉化了的Labels.png

像一點可見的反饋,我們想去增加渦輪旋轉的頻率當風速增加時(注意,這些值僅僅是為了教育的目的,而且完全沒有從風里獲取能量的物理學基礎)。
這個TurbineView控制了動畫,但是我們需要去提供每秒刀片旋轉的角度。你可能定義了一個在類里的屬性,就像下面這樣:

 /// The angle the blades rotate per second, in radians.
 public var bladeRotationPerSecond: Double

這是OK的并且遵循了蘋果的API ,角度被弧度所提供。然而你怎么去阻止那些提供這些值時使用角度的用戶 。你可能會說:“那時應該去讀說明文檔”。
這個參數可能有一些優點,然而假使這個屬性沒有任何說明會怎樣?它也會是一個相當簡單的錯,對于大多數所習慣思考度數的角度的我們。
我們如何使用Measurement,限制僅僅接受有關角度的單位?這個
我們可以允許用戶提供任何他們覺得最舒服的角度并且在內部轉化成任何我們需要的值。聽起來很棒,讓我們給出一段:

// TurbineView property
public var bladeRotationPerSecond: Measurement<UnitAngle> =    Measurement(value: 0, unit: UnitAngle.degrees) {
didSet {
  rotate()
}

}

在我們的視圖控制器我們可以決定每秒的循環用以下的代碼:

fun calculateTurbineRotation() {
// If we assume max value of slider = 1 rotation per second
let ratio = windSpeedSlider.value / windSpeedSlider.maximumValue

let fullRotation = Measurement(value: 360, unit: UnitAngle.degrees)

let rotationAnglePerSecond = fullRotation * Double(ratio)

turbine.bladeRotationPerSecond = rotationAnglePerSecond

}

我們可以用我們覺得最舒服的角度單位 --我選擇了角度。那之后我們使用基于當前的風速來容易的乘法操作去獲取旋轉的角度(如果滑塊值為0,那速率將會是0/40=0,反之在數值范圍的最后如果滑塊的值為40那么速率將會是40/40=1)。
在這我們有了我們自己美麗的風力渦輪。

原文地址:[iOS 10 Day by Day :: Day 7 :: Measurement](https://www.shinobicontrols.com/blog/ios-10-day-by-day-day-7-measurement)
原作者:Sam Burnstone @sam_burnstone
ShinobiControls 官網:ShinobiControls.com twitter : @shinobicontrols
譯者:simpleton king

看了戴倉薯的daybyday文章,突然就想自己也翻一篇,第一次翻譯文章,如果有什么翻的不好的地方,敬請指正。之前的daybyday可以到戴倉薯的文集(http://www.lxweimin.com/notebooks/5278512/latest) 瀏覽。
順便求個幫助,大家iOS10下面canlebypruduce的resumedata有出問題么 ?導致不能繼續重新下載。
查了下stackoverflow,有說是apple的bug。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 《iOS 10 day by day》是 shinobicontrols 公司編寫的系列博客,介紹開發者需要了解的...
    戴倉薯閱讀 1,353評論 0 5
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,200評論 30 471
  • 天一丹走在又冷又黑的小巷,風衣在黑夜中嗦嗦作響,黃昏在世界的另一邊,韓胡曉甩著雙手,慢悠悠的走在在三三兩兩有情人...
    墨跡哼出閱讀 191評論 0 1
  • 今年的夏天,好像比往年來的更早一些。 他穿著件白色T恤,黑色阿迪短褲,白色鞋幫已經有些泛黃的匡威布鞋。 為了躲避中...
    用屁股思考2017閱讀 341評論 0 0