我正在观看WWDC2014上的一些视频并试图编写我喜欢的代码,但我注意到的一个奇怪的事情是Swift一直对我生气并希望我投射到不同的数字类型。这很容易,但在WWDC的视频中他们不需要这样做。以下是“界面生成器的新功能”中的示例:
-M_PI / 2一直给我错误:“无法找到接受提供的参数的'/'重载'
有没有人有这个问题的解决方案,这不仅仅涉及投射,因为有明显的另一种方法吗?对于类似问题,我还有很多例子。
if !ringLayer {
ringLayer = CAShapeLayer()
let innerRect = CGRectInset(bounds, lineWidth / 2.0, lineWidth / 2.0)
let innerPath = UIBezierPath(ovalInRect: innerRect)
ringLayer.path = innerPath.CGPath
ringLayer.fillColor = nil
ringLayer.lineWidth = lineWidth
ringLayer.strokeColor = UIColor.blueColor().CGColor
ringLayer.anchorPoint = CGPointMake(0.5, 0.5)
ringLayer.transform = CATransform3DRotate
(ringLayer.transform, -M_PI/2, 0, 0, 1)
layer.addSublayer(ringLayer)
}
ringLayer.frame = layer.bounds
答案 0 :(得分:6)
编辑:NB:CGFloat在beta 4中发生了变化,特别是为了更容易处理这个32/64位差异。阅读发行说明,现在不要将下面作为福音:它是为beta 2编写的。
来自this answer的线索我已经解决了:它取决于所选的项目架构。如果我将Project架构保留为默认值(armv7,arm64),那么我会得到与此代码相同的错误:
// Error with arm7 target:
ringLayer.transform = CATransform3DRotate(ringLayer.transform, -M_PI/2, 0, 0, 1)
...并且需要施放到Float(好吧,下面的CGFloat,我敢肯定)让它工作:
// Works with explicit cast on arm7 target
ringLayer.transform = CATransform3DRotate(ringLayer.transform, Float(-M_PI/2), 0, 0, 1)
但是,如果我仅将目标体系结构更改为arm64,则代码的工作方式与视频中的Apple示例相同:
// Works fine with arm64 target:
ringLayer.transform = CATransform3DRotate(ringLayer.transform, -M_PI/2, 0, 0, 1)
所以回答你的问题,我相信这是因为CGFloat被定义为64位架构的双倍,所以可以使用M_PI(也是一个双倍)来源的值作为CGFloat参数。但是,当arm7是目标时,CGFloat是一个浮点数,而不是一个双精度数,因此当将M_PI(仍为双精度)表达式直接作为CGFloat参数传递时,您将失去精度。
请注意,Xcode默认只为Debug版本的“主动”架构构建 - 我发现可以通过在菜单栏的标准下拉菜单中切换iPhone 4S和iPhone 5S方案来切换此错误。 Xcode,因为它们有不同的架构。我想在演示视频中,选择了64位架构目标,但在您的项目中,您选择了32位架构?
鉴于CGFloat在64位体系结构上是双精度的,处理这个特定问题的最简单方法是始终转换为CGFloat。
但是,当您需要在不同的体系结构上执行不同的操作时,作为处理此类问题的演示,Swift确实支持conditional compilation:
#if arch(x86_64) || arch(arm64)
ringLayer.transform = CATransform3DRotate (ringLayer.transform, -M_PI / 2, 0, 0, 1)
#else
ringLayer.transform = CATransform3DRotate (ringLayer.transform, CGFloat(-M_PI / 2), 0, 0, 1)
#endif
然而,这只是一个例子。你真的不希望在任何地方做这种事情,所以我一定会坚持使用CGFloat(<whatever POSIX double value you need>)
来获得32位或64位的值取决于目标架构。
Apple在以后的编译器版本中为处理不同的浮点数添加了更多帮助 - 例如,在早期的测试版中,你甚至无法轻易地获取单精度浮点数的floor()
,而现在(当前Xcode 6.1) )对于float和double都有floor()
,ceil()
等的覆盖,所以你不需要摆弄条件编译。
答案 1 :(得分:0)
目前在Objective C数字类型和Swift类型之间的自动转换似乎存在问题。为此,我能够通过将lineWidth标记为Float类型来使其工作。我不知道他们为什么在视频中没有这个问题,我认为这是他们使用的不同版本。我缺少一个Objective C互操作设置,或者它只是一个测试版问题。
为了验证我使用的一些基本问题(甚至在Playground中发生):
var x:NSNumber = 1
var y:Integer = 2
var z:Int = 3
x += 5 //error
y += 6 //error
z = z + y //error
答案 2 :(得分:0)
对于Swift 1.2
,您必须将第二个参数投射到CGFloat
此代码有效:
ringLayer.transform = CATransform3DRotate(ringLayer.transform, CGFloat(-M_PI/2), 0, 0, 1)