加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

swift – CGFloat和NSNumber之间的转换,没有不必要的升级到Doubl

发布时间:2020-12-14 02:26:20 所属栏目:百科 来源:网络整理
导读:众所周知,CGFloat(在CoreGraphics,UIKit等中无处不在) 可以是32位或64位浮点数,具体取决于 处理器架构. 在C,CGFloat中它是一种类型 浮点数或双精度数,在Swift中定义为带有的结构CGFloat 本地属性(Float或Double). 已经反复观察到可以从中创建NSNumber 并转换
众所周知,CGFloat(在CoreGraphics,UIKit等中无处不在)
可以是32位或64位浮点数,具体取决于
处理器架构.

在C,CGFloat中它是一种类型
浮点数或双精度数,在Swift中定义为带有的结构CGFloat
本地属性(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?

请注意,这是一个“学术”问题.如上所述
在上面(以及在其他Q& A中),可以简单地通过Double进行转换
几乎.

我在这里发布了一个“自我回答”的精神
share your knowledge,Q&A-style.当然欢迎其他答案!

更新:可以将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,&value)
        return value
    }
}

这很简单.唯一的缺点:我无法弄清楚
如何使构造函数成为init方法而不是类方法.

第二种可能的解决方案有点长:

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())
    }
}

有两个私有的“helper”init方法具有相同的外部
参数名称为doubleOrFloat但参数类型不同.从实际出发
cgFloat.native的类型,编译器确定调用哪一个

convenience init(cgFloat : CGFloat) {
        self.init(doubleOrFloat: cgFloat.native)
    }

访问器方法中的相同想法.从self.native的类型
编译器确定两个doubleOrFloatValue()中的哪一个
要打电话的方法

var cgFloatValue : CGFloat {
        return CGFloat(floatLiteral: doubleOrFloatValue())
    }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读