【问题标题】:Swift numerics and CGFloat (CGPoint, CGRect, etc.)Swift 数字和 CGFloat(CGPoint、CGRect 等)
【发布时间】:2014-07-29 07:37:06
【问题描述】:

我发现 Swift 数字特别笨拙,因为在现实生活中经常发生这种情况,我必须与 Cocoa Touch 就 CGRect 和 CGPoint 进行交流(例如,因为我们谈论的是 frame 或 @987654323 @)。

CGFloat 与 Double

考虑以下来自 UIViewController 子类的看似无辜的代码:

let scale = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.size.width * scale

此代码编译失败,最后一行出现通常的神秘错误:

找不到接受提供的参数的“*”的重载

我相信您现在已经知道这个错误,表明类型之间存在某种阻抗不匹配。 r.size.width 以 CGFloat 的形式出现,它将自动与 Swift Float 互换,但不能与 Swift Double 变量互操作(默认情况下,scale 就是这样)。

该示例人为地简短,因此有一个人为的简单解决方案,即从一开始就将scale 转换为浮点数。但是,当从各地提取的许多变量都涉及到提议的 CGRect 元素的计算中时,需要进行大量的转换。

详细初始化程序

另一个令人烦恼的事情是在创建新的 CGRect 时会发生什么。尽管有文档,但没有带有值但没有标签的初始化程序。这无法编译,因为我们有 Doubles:

let d = 2.0
var r3 = CGRect(d, d, d, d)

但即使我们将d 转换为浮点数,我们也不会编译:

调用中缺少参数标签“x:y:width:height:”

所以我们最终回到CGRectMake,这对Objective-C没有任何改进。有时 CGRectMake 和 CGSizeMake 并没有改善。考虑一下我的一个应用程序中的这段实际代码:

let kSEP : Float = 2.0
let intercellSpacing = CGSizeMake(kSEP, kSEP);

在我的一个项目中,这是可行的。另一方面,它神秘地失败了——完全相同的代码! — 出现此错误:

“NSNumber”不是“CGFloat”的子类型

就好像,有时,Swift 试图通过将 Float 强制转换为 NSNumber 来“过桥”,当桥的另一边需要 CGFloat 时,这当然是错误的做法。我还没有弄清楚这两个项目之间的区别是什么导致错误出现在一个而不是另一个(也许其他人有)。

注意:我可能已经发现了这个问题:它似乎取决于 Build Active Architecture Only 构建设置,这反过来表明这是一个 64 位问题。这是有道理的,因为 Float 与 64 位设备上的 CGFloat 不匹配。这意味着阻抗失配问题比我想象的还要严重。

结论

我正在寻找关于这个话题的实用智慧之言。我想有人可能设计了一些 CGRect 和 CGPoint 扩展,这将使生活变得更轻松。 (或者可能有人写了一大堆额外的算术运算符函数重载,这样将 CGFloat 与 Int 或 Double 结合起来“就行了”——如果可能的话。)

【问题讨论】:

  • 您是在 Open Radar 上提交错误报告,还是仅私下提交?
  • @JoshCaswell 私下,但如果您需要雷达编号和措辞,请离线联系我
  • 在 Xcode 6 beta 5 中:CGFloat 可以从任何 Integer 类型(包括大小整数类型)构造,反之亦然。 (17670817)
  • 好消息,感谢@BergQuester 的提醒

标签: ios swift


【解决方案1】:

正如您所发现的,将scale 显式输入到CGFloat 确实是快速处理输入问题的方法。供他人参考:

let scale: CGFloat = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.width * scale

不确定如何回答您的第二个问题,您可能想用不同的标题单独发布。

更新:

Swift 的创造者和首席开发者 Chris Lattner 于 2014 年 7 月 4 日在Apple Developer Forum 上就这个问题发表了这样的看法:

这里发生的是 CGFloat 是 Fl​​oat 的类型别名 或 Double 取决于您是为 32 位还是 64 位构建。 这正是 Objective-C 的工作方式,但在 Swift 中存在问题 因为 Swift 不允许隐式转换。

我们知道 这个问题并认为它很严重:我们正在评估几个 现在有不同的解决方案,并将在以后的测试版中推出。 正如您所注意到的,您今天可以通过转换为 Double 来解决这个问题。 这是不优雅但有效的:-)

Xcode 6 Beta 5 中的更新:

CGFloat 可以由任何 Integer 类型(包括 大小的整数类型),反之亦然。 (17670817)

【讨论】:

  • 抛开个人喜好不谈,这就是快速处理打字问题的方式。 Apple 正在寻找有关该语言的反馈,所以我相信他们会愿意收到一些反馈。
  • 完全正确。使用CGFloats 时,您必须将所有内容键入CGFloat。很简单。
  • @Sulthan 是的,但问题是当你说“一切”时,你真正的意思是“一切”。例如,如果f 是 CGFloat 而d 是 Double(这是默认值),则不能将它们相乘。因此,正如我在问题中所说,有很多演员要做。但这太疯狂了。
  • @Sulthan 我提交了一个错误。在 Objective-C 中,一旦某个东西是 CGFloat,所有数值运算都可以正常工作,并且与 CGRect 和 CGPoint 的信息交换在 32 位和 64 位平台上都可以正常工作。毕竟,如果没有这种易用性来满足 iOS 编程中最常见的需求之一,这种语言的使用将会非常令人生畏。
  • @Sulthan 我没有说这是一个错误,我说我提交了一个错误报告。如果它变得如此挑剔,没有人会想要使用这种语言。 - 不要误会我的意思,与 Objective-C 相比,Swift 有很多伟大。但这不是那个。为什么不是最好的?苹果的目标应该比这更高。
【解决方案2】:

我为 Double 和 Int 创建了一个扩展,向它们添加了一个计算的 CGFloatValue 属性。

extension Double {
    var CGFloatValue: CGFloat {
        get {
            return CGFloat(self)
        }
    }
}
extension Int {
    var CGFloatValue: CGFloat {
        get {
            return CGFloat(self)
        }
    }
}

您可以使用 let someCGFloat = someDoubleOrInt.CGFloatValue 访问它

此外,对于您的 CGRect 初始化程序,您会收到缺少参数标签的错误,因为您已经离开了标签,您需要 CGRect(x: d, y: d, width: d, height: d) 除非只有一个参数,否则您不能离开标签。

【讨论】:

    【解决方案3】:

    我编写了一个处理运算符重载的库,以允许 Int、CGFloat 和 Double 之间的交互。

    https://github.com/seivan/ScalarArithmetic

    从 Beta 5 开始,这里列出了您目前无法使用原版 Swift 执行的操作。 https://github.com/seivan/ScalarArithmetic#sample

    我建议在使用和不使用 ScalarArithmetic 的情况下运行测试套件,看看发生了什么。

    【讨论】:

    • Apple 应该将其纳入语言中。
    • @SSS 你误解了克里斯所说的话。他们正在评估解决方案,我认为他们不会添加隐式转换。
    • @Sulthan 谢谢这更有意义。
    • 在 Xcode 6 beta 5 中:CGFloat 可以从任何 Integer 类型(包括大小整数类型)构造,反之亦然。 (17670817)
    • 截至 2015 年 4 月 6 日,该项目似乎已被放弃。最后一次提交是 8 个月前,它不能用 Xcode 6.2 编译
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-15
    • 2012-08-17
    相关资源
    最近更新 更多