node.physicsBody.joints 向下转型错误

node.physicsBody.joints downcasting error

以下代码出现错误 - 物理关节数组似乎具有 class PKPhysicsJoint。任何人都知道如何遍历 Swift?

中的关节

documentation 确实说 physicsBody.joints 应该 return 一个 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...

更新:这个一个错误,它已在iOS 9 / OS X 10.11 — 问题中的代码现在可以正常工作了。

为后代/使用旧版 SDK 的人等留下原始答案文本


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

如果您将代码粘贴到 playground 中,问题就很明显了——您的 joint 实际上是幕后的 PKPhysicsJointWeld。这是一些内部 class 应该是一个实现细节。在 ObjC 中这没有问题,因为在 C 中进行转换只是告诉编译器 "trust me, this pointer is really an SKPhysicsJoint, so let me call physics joint methods (and nothing else) on it and and no one will be the wiser" 的问题。在 Swift 中进行转换要求转换类型之间存在类型层次关系 — 而 PKPhysicsJointWeld 不是 SKPhysicsJoint 的 subtype/subclass,因此转换失败。

您可以通过避免强制转换为 [SKPhysicsJoint]:

来解决此问题
for joint in nodeA.physicsBody!.joints {
    // do something else here
}

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

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

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

这会让你恢复一点编译时类型 "safety",因为此后编译器将要求你对 skJoint 所做的任何事情都与 SKPhysicsJoint 兼容,但是它本质上仍然是不安全的,因为它依赖于一些可能并不总是有效的运行时类型。而且你必须再次 unsafeBitCast 才能到达特定的联合子 class,而不知道它可能是哪个子class。 (同样,this would be a good time to file a bug。)


(通过粘贴到 playground,您可能会注意到 physicsWorld 也是内部 class:PKPhysicsWorld。那为什么它也不会失败呢?当您使用 physicsWorld 属性,所有类型转换都发生在 ObjC 端,并且 Swift 相信 ObjC 告诉它的任何内容。但是,当你处理 joints 数组时,你必须在 Swift 端进行类型转换,而 Swift 对类型检查要严格得多。)