Swift数字和CGFloat(CGPoint,CGRect等)

mat*_*att 60 ios swift

我发现Swift数字尤其笨拙,正如在现实生活中经常发生的那样,我必须就CGRect和CGPoint与Cocoa Touch进行沟通(例如,因为我们正在谈论某些事情frame或者bounds).

CGFloat vs. Double

从UIViewController子类中考虑以下看似无辜的代码:

let scale = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.size.width * scale
Run Code Online (Sandbox Code Playgroud)

此代码无法编译,最后一行通常有神秘错误:

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

正如我现在所知道的那样,这个错误表明类型之间存在某种阻抗不匹配.r.size.width作为CGFloat到达,它将与Swift Float自动交换,但不能与Swift Double变量(默认情况下是这样scale)进行互操作.

这个例子是人为简短的,所以有一个人为简单的解决方案,即scale从一开始就转换为Float.但是当从所有地方抽取的许多变量都参与了CGRect元素的计算时,需要进行大量的投射.

详细初始化器

另一个恼人的是当创建新的CGRect时会发生什么.尽管有文档,但没有带有值但没有标签的初始值设定项.这无法编译,因为我们有双打:

let d = 2.0
var r3 = CGRect(d, d, d, d)
Run Code Online (Sandbox Code Playgroud)

但即使我们d转向Float,我们也不会编译:

在调用中缺少参数标签'x:y:width:height:'

所以我们最终会重新开始CGRectMake,这对Objective-C没有任何改进.有时CGRectMake和CGSizeMake没有任何改进.请考虑我的某个应用中的实际代码:

let kSEP : Float = 2.0
let intercellSpacing = CGSizeMake(kSEP, kSEP);
Run Code Online (Sandbox Code Playgroud)

在我的一个项目中,这是有效的.在另一个,它神秘失败 - 完全相同的代码! - 出现此错误:

'NSNumber'不是'CGFloat'的子类型

有时,Swift试图通过将Float转换为NSNumber来"过桥",当桥的另一侧需要CGFloat时,这当然是错误的.我还没有弄清楚导致错误出现在一个而不是另一个(可能是其他人有)的两个项目之间的区别.

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

结论

我正在寻找关于这个主题的实用智慧词.我想有人可能已经设计了一些CGRect和CGPoint扩展,这将使生活变得更加容易.(或者可能有人写了一大堆额外的算术运算符函数重载,这样将CGFloat与Int或Double结合起来"只是起作用" - 如果可能的话.)

Ber*_*ter 24

明确打字scaleCGFloat,因为你已经发现,确实是这样处理的打字问题迅速.供他人参考:

let scale: CGFloat = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.width * scale
Run Code Online (Sandbox Code Playgroud)

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

更新:

Swift创建者和首席开发人员Chris Lattner在2014年7月4日的Apple开发者论坛上就此问题发表了这样的话:

这里发生的是CGFloat是Float或Double的类型,具体取决于你是构建32位还是64位.这正是Objective-C的工作方式,但在Swift中存在问题,因为Swift不允许隐式转换.

我们已经意识到这个问题并认为它是严肃的:我们现在正在评估几种不同的解决方案,并将在稍后的测试版中推出一个.正如您所注意到的,您可以通过强制转换为Double来应对此问题.这是不优雅但有效的:-)

在Xcode 6 Beta 5中更新:

CGFloat可以从任何Integer类型(包括大小的整数类型)构造,反之亦然.(17670817)

  • @Sulthan是的,但问题是,当你说"一切"时,你的意思是"一切".例如,如果`f`是CGFloat并且`d`是Double(这是默认值),则不能将它们相乘.因此,正如我在我的问题中所说的那样,有很多事要做.但那太疯狂了. (5认同)
  • @Sulthan我没有说这是一个bug,我说我提交了一个错误报告.没有人会想要使用这种语言,如果这将是挑剔的. - 不要误会我的意思,与Objective-C相比,Swift有很多_great_.但事实并非如此.为什么不是最好的?Apple的目标应该高于此. (4认同)
  • @Sulthan我提交了一个错误.在Objective-C中,一旦某个东西是CGFloat,所有数值运算都可以正常工作,并且与CGRect和CGPoint的信息交换在32位和64位平台上都能正常工作.毕竟,在iOS编程中最常见的需求之一,如果没有这种易用性,这种语言将会非常令人畏惧. (3认同)

Sei*_*van 15

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

https://github.com/seivan/ScalarArithmetic

从Beta 5开始,这里列出了目前你无法用vanilla Swift做的事情. https://github.com/seivan/ScalarArithmetic#sample

我建议运行带有和不带ScalarArithmetic的测试套件,看看是怎么回事.

  • Apple应该将其融入语言中. (3认同)

And*_*97p 6

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

extension Double {
    var CGFloatValue: CGFloat {
        get {
            return CGFloat(self)
        }
    }
}
extension Int {
    var CGFloatValue: CGFloat {
        get {
            return CGFloat(self)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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