[英]Swift numerics and CGFloat (CGPoint, CGRect, etc.)
我发现Swift数字尤其笨拙,正如在现实生活中经常发生的那样,我必须就CGRect和CGPoint与Cocoa Touch进行沟通(例如,因为我们谈论的是frame
或bounds
)。
从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
到Float。 但是当从所有地方抽取的许多变量都参与了CGRect元素的计算时,需要进行大量的投射。
另一个恼人的是当创建新的CGRect时会发生什么。 尽管有文档,但没有带有值但没有标签的初始值设定项。 这无法编译,因为我们有双打:
let d = 2.0
var r3 = CGRect(d, d, d, d)
但即使我们将d
转换为Float,我们也不会编译:
在调用中缺少参数标签'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结合起来“只是工作” - 如果可能的话。)
正如您所发现的那样,明确scale
向CGFloat
键入scale
确实是处理swift中的键入问题的方法。 供他人参考:
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开发者论坛上就此问题发表了这样的话:
这里发生的是CGFloat是Float或Double的类型,具体取决于你是构建32位还是64位。 这正是Objective-C的工作方式,但在Swift中存在问题,因为Swift不允许隐式转换。
我们已经意识到这个问题并认为它是严肃的:我们现在正在评估几种不同的解决方案,并将在稍后的测试版中推出一个。 正如您所注意到的,您可以通过强制转换为Double来应对此问题。 这是不优雅但有效的:-)
在Xcode 6 Beta 5中更新:
CGFloat可以从任何Integer类型(包括大小的整数类型)构造,反之亦然。 (17670817)
我写了一个处理运算符重载的库,允许Int,CGFloat和Double之间的交互。
https://github.com/seivan/ScalarArithmetic
从Beta 5开始,这里列出了目前你无法用vanilla Swift做的事情。 https://github.com/seivan/ScalarArithmetic#sample
我建议运行带有和不带ScalarArithmetic的测试套件,看看是怎么回事。
我为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)
你不能留下标签除非只有一个论点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.