[iOS 10 day by day] Day 7:Measurement

在iPhone7发布之后,令人兴奋的事情已经尘埃落定,现在是时候继续看看iOS10提供的新特性
这一周我们将要看看新的Measurement API:the Foundation framework的新部分。从表面上看,它看起来并不是都那么兴奋:它提供了一种在计量单位间转化的方式就像公里和英里。

然而,当你仔细思考它,我们花费了极多的时间去转化值。这可能发生在由于你有角度,但是你所用来旋转视图所用的API要求用弧度。可选择的,可能因为你的应用用英里计算距离,但是你需要为了那些更喜欢用公里单位的用户去转换成公里单位。
在iOS10之前,你可能有创造自己的函数去转换值乘其它的单位或者用外部库。现在苹果已经为你提供了有很大操控提升的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。它做了完美的表现,令我们可以合适的在这个组中转换成其它的值。毕竟,我们如何才能转换一公升的水成一公里。

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就像下面这样

[iOS 10 day by day] Day 7:Measurement_第1张图片
未转化的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和英里每小时量度。

[iOS 10 day by day] Day 7:Measurement_第2张图片
转化了的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 =    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.jianshu.com/notebooks/5278512/latest) 浏览。
顺便求个帮助,大家iOS10下面canlebypruduce的resumedata有出问题么 ?导致不能继续重新下载。
查了下stackoverflow,有说是apple的bug。

你可能感兴趣的:([iOS 10 day by day] Day 7:Measurement)