【发布时间】:2016-03-21 23:21:01
【问题描述】:
众所周知,CGFloat(在 CoreGraphics、UIKit 等中无处不在)
可以是 32 位或 64 位浮点数,具体取决于
处理器架构。
在 C 中,CGFloat 是一个类型别名
到 float 或 double,在 Swift 中它被定义为 struct CGFloat
一个native 属性(即Float 或Double)。
反复观察到NSNumber 可以从
并转换为Float 和Double,但不存在
与CGFloat 之间的类似转换。一般建议
(例如在Convert CGFloat to NSNumber in Swift)是
通过Double转换
CGFloat <--> Double <--> NSNumber
例子:
let c1 = CGFloat(12.3)
let num = NSNumber(double: Double(c1))
let c2 = CGFloat(num.doubleValue)
这是简单而正确的,不会丢失任何精度。
现在大多数平台都是 64 位的,然后是 CGFloat/Double
转换很简单,可能已被编译器优化。
但是,如果可以进行转换,这引起了我的好奇心
没有在 32 位平台上将 CGFloat 提升为 Double。
可以使用构建配置语句(例如在Should conditional compilation be used to cope with difference in CGFloat on different architectures? 中):
extension NSNumber {
convenience init(cgFloatValue value : CGFloat) {
#if arch(x86_64) || arch(arm64)
self.init(double: value.native)
#else
self.init(float: value.native)
#endif
}
}
但是如果 Swift 被移植到其他不支持的架构中会怎样? 英特尔还是 ARM?这看起来不太适合未来。
也可以使用CGFLOAT_IS_DOUBLE 常量(例如在
NSNumber from CGFloat):
if CGFLOAT_IS_DOUBLE != 0 {
// ...
} else {
// ...
}
这里的缺点是编译器总是会发出一个 “永远不会被执行”警告其中一种情况。
长话短说:
- 我们如何转换
CGFloat和NSNumber以安全的方式,没有编译器警告, 并且没有对Double的不必要的提升?
请注意,这是一个“学术”问题。如前所述
上面(以及其他问答中)可以通过Double 简单地转换
实际上。
本着 share your knowledge, Q&A-style。当然也欢迎其他答案!
【问题讨论】: