node.physicsBody.joints向下转换错误

时间:2015-02-13 14:30:27

标签: swift sprite-kit skphysicsbody skphysicsjoint

以下代码给出了错误 - 看起来物理关节数组具有类PKPhysicsJoint。任何人都有任何想法如何迭代Swift中的关节?

documentation确实说physicsBody.joints应该返回一个SKPhysicsJoint数组。

import SpriteKit

let scene = SKScene(size: CGSize(width: 200, height: 200))
let nodeA = SKNode()
let nodeB = SKNode()

nodeA.physicsBody = SKPhysicsBody(circleOfRadius: 20)
nodeB.physicsBody = SKPhysicsBody(circleOfRadius: 20)

scene.addChild(nodeA)
scene.addChild(nodeB)

let joint = SKPhysicsJointFixed.jointWithBodyA(nodeA.physicsBody, bodyB: nodeB.physicsBody, anchor: CGPointZero)
scene.physicsWorld.addJoint(joint)

for joint in nodeA.physicsBody!.joints as [SKPhysicsJoint] {
  // do something else here
}

给出错误:

Execution was interrupted. reason: EXC_BAD_INSTRUCTION...

1 个答案:

答案 0 :(得分:3)

更新 :这个 是一个错误,它在iOS 9 / OS X 10.11中得到修复 - 问题中的代码现在正常运行

使用较旧的SDK /等为后代/伙伴留下原始答案文本。


这看起来像一个错误 - you should file it。是否应将其视为SpriteKit错误或Swift错误很难说,但这是Apple的问题,而不是你的问题。 :)

如果您将代码粘贴到游乐场,问题就很明显了 - 您的joint实际上是幕后的PKPhysicsJointWeld。这是一个应该是实现细节的内部类。在ObjC中没有问题,因为在C中进行转换只是告诉编译器,“相信我,这个指针实际上是一个SKPhysicsJoint,所以让我在它上面调用物理联合方法(而不是别的)和没有人会更聪明“。在Swift中进行转换要求在转换类型之间存在类型层次结构关系 - 而PKPhysicsJointWeld不是SKPhysicsJoint的子类型/子类,因此转换失败。

您可以通过避免转换为[SKPhysicsJoint]来解决此问题:

for joint in nodeA.physicsBody!.joints {
    // do something else here
}

有了这个,你会失去一些类型安全性 - jointAnyObject,所以像ObjC的id类型一样,编译器允许你调用它上面的任何方法。 (如果该对象没有实现该方法,它可能在运行时失败。)但至少它运行。

进一步的解决方法:在循环内部,您可以将joint投射到SKPhysicsJoint。但由于该转换是跨越类型层次结构,因此您必须使用unsafeBitCast

for joint in nodeA.physicsBody!.joints {
    let skJoint = unsafeBitCast(joint, SKPhysicsJoint.self)
    // do stuff with skJoint
}

这会让你得到一些编译时类型“安全”,之后编译器会要求你使用skJoint做的任何事情都与SKPhysicsJoint兼容,但它本身仍然不安全因为它取决于一些可能并不总是持有的运行时类型。并且您必须再次unsafeBitCast才能访问特定的联合子类,而不知道它可能是哪个子类。 (再次,this would be a good time to file a bug。)


(你可能会注意到,physicsWorld也是一个内部类的游乐场:PKPhysicsWorld。那么为什么不会失败呢?当你使用{{1}时}属性,所有类型转换都发生在ObjC端,而Swift信任ObjC告诉它的任何东西。当你处理physicsWorld数组时,你必须在Swift端做一个类型转换,而Swift是对类型检查要严格得多。)