众所周知,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 {
// ...
}
这里的缺点是编译器总会发出一个 &#34;永远不会执行&#34; 警告其中一个案例。
所以长话短说:
CGFloat
和NSNumber
以安全的方式,没有编译器警告,
没有不必要的促销Double
?请注意,这是一个&#34;学术&#34;问题。如上所述
以上(以及其他Q&amp; A&#39; s)可以通过Double
进行转换
实际上。
我发布了一个&#34;自我回答&#34;在这里的精神 share your knowledge, Q&A-style。当然欢迎其他答案!
答案 0 :(得分:12)
更新:可以将CGFloat
值转换为NSNumber
并返回:
let c1 = CGFloat(12.3)
let num = c1 as NSNumber
let c2 = num as CGFloat
这保留了CGFloat
的精度,并与Swift 2一起使用
和斯威夫特3。
(以前的答案 - 太复杂了):我找到了两个解决方案。第一个使用免费桥接
在NSNumber
和CFNumber
之间(如What is most common and correct practice to get a CGFloat from an NSNumber?中所示)
for Objective-C)。它使用CFNumber
具有专用的事实
CGFloat
值的转换模式:
extension NSNumber {
// CGFloat -> NSNumber
class func numberWithCGFloat(var value: CGFloat) -> NSNumber {
return CFNumberCreate(nil , .CGFloatType, &value)
}
// NSNumber -> CGFloat
var cgFloatValue : CGFloat {
var value : CGFloat = 0
CFNumberGetValue(self, .CGFloatType, &value)
return value
}
}
这很简单。唯一的缺点:我无法弄清楚
如何使构造函数成为init
方法而不是class method
。
第二种可能的解决方案有点长:
extension NSNumber {
// CGFloat -> NSNumber
private convenience init(doubleOrFloat d : Double) {
self.init(double : d)
}
private convenience init(doubleOrFloat f : Float) {
self.init(float : f)
}
convenience init(cgFloat : CGFloat) {
self.init(doubleOrFloat: cgFloat.native)
}
// NSNumber -> CGFloat
private func doubleOrFloatValue() -> Double {
return self.doubleValue
}
private func doubleOrFloatValue() -> Float {
return self.floatValue
}
var cgFloatValue : CGFloat {
return CGFloat(floatLiteral: doubleOrFloatValue())
}
}
有两个私人&#34;帮手&#34; init方法与外部相同
参数名称doubleOrFloat
但参数类型不同。从实际出发
编译器确定调用哪一个cgFloat.native
的类型
在
convenience init(cgFloat : CGFloat) {
self.init(doubleOrFloat: cgFloat.native)
}
访问器方法中的相同想法。来自self.native
的类型
编译器确定两个doubleOrFloatValue()
中的哪一个
要调用的方法
var cgFloatValue : CGFloat {
return CGFloat(floatLiteral: doubleOrFloatValue())
}
答案 1 :(得分:0)
let num = NSNumber(double: 1.0)
let c: CGFloat? = CGFloat(exactly: num)
这是初始化程序的documentation。