Swift数字和CGFloat(CGPoint,CGRect等)

我发现Swift数字特别笨拙,因为在现实生活中经常发生,我不得不与Cocoa Touch就CGRect和CGPoint进行交stream(例如,因为我们正在讨论某些framebounds )。

CGFloat与Double

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

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

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

无法find接受提供参数的“*”的重载

这个错误,正如我现在知道的那样,表示某种types的阻抗不匹配。 r.size.width作为CGFloat到达,它将自动与Swift Float交换,但不能与Swift Doublevariables(默认情况下是什么scale )交互操作。

这个例子是人为的简单的,所以有一个人为的简单的解决办法,就是从一开始就把scale到浮动。 但是,当计算一个被提议的CGRect元素的时候,很多变数都会涉及到,这里有很多的转换要做。

详细的初始化程序

另一个刺激是什么时候来创build一个新的CGRect。 尽pipe文档,没有值的初始值设定项,但没有标签。 由于我们有双打,因此无法编译:

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

但是,即使我们将d转换为Float,我们也不会编译:

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

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

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

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

“NSNumber”不是“CGFloat”的子types

有时,Swift有时试图通过将一个Float转换为一个NSNumber来“跨越桥梁”,当桥梁的另一端需要一个CGFloat的时候,这当然是错误的。 我还没有弄清楚导致错误出现在一个而不是另一个(也许别人有)的两个项目之间的区别。

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

结论

我正在寻找关于这个话题的实际智慧词汇。 我想有人可能已经devise了一些CGRect和CGPoint扩展,这将使生活变得更容易。 (或者可能有人编写了一堆附加的算术运算符函数重载,这样将CGFloat与Int或Double结合起来“正常工作” – 如果可能的话)。

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

https://github.com/seivan/ScalarArithmetic

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

我build议使用和不使用ScalarArithmetic来运行testing套件,只是为了看看发生了什么。

正如你所发现的那样,明确scaleCGFloatinput到CGFloat中的确是快速处理input问题的方法。 供他人参考:

 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日的苹果开发者论坛上就这个问题发表了看法:

这里发生的事情是,CGFloat是Float或Double的一个typealias,取决于你是在build立32位还是64位。 这正是Objective-C的工作原理,但在Swift中存在问题,因为Swift不允许隐式转换。

我们意识到这个问题,并认为它是严重的:我们正在评估几个不同的解决scheme,并将在以后的testing版中推出。 正如你注意到的,你今天可以通过投掷到Double来应付这个问题。 这不雅但有效:-)

在Xcode 6 Beta 5中更新:

一个CGFloat可以从任何Integertypes(包括大小的整数types)构build,反之亦然。 (17670817)

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

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

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

此外,至于你的CGRect初始化,你得到缺less的参数标签错误,因为你已经离开标签,你需要CGRect(x: d, y: d, width: d, height: d)你不能离开标签除非只有一个论点。