node.physicsBody.joints ошибка downcasting

Следующий код выдает ошибку - кажется, что массив физических соединений имеет класс PKPhysicsJoint. У кого-нибудь есть идеи, как я могу перебирать соединения в Swift?

В документации сказано, что physBody.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 ответ

Решение

Обновление: это была ошибка, и она исправлена ​​в iOS 9 / OS X 10.11 - код в вопросе только сейчас работает.

Оставить оригинальный текст ответа для потомков / людей, использующих старые SDK / и т. Д.


Это похоже на ошибку - вы должны подать его. Трудно сказать, следует ли считать это ошибкой SpriteKit или Swift, но это проблема Apple, а не ваша.:)

Проблема ясна, если вы вставите свой код в игровую площадку - ваш joint на самом деле PKPhysicsJointWeld за кулисами. Это некоторый внутренний класс, который должен быть деталью реализации. В ObjC это не проблема, потому что приведение в C - это просто сказать компилятору: "Поверьте мне, этот указатель действительно SKPhysicsJointтак что позвольте мне назвать физические совместные методы (и ничто иное) для него, и никто не станет мудрее ". Приведение в Swift требует, чтобы между приведенными типами были отношения иерархии типов - и PKPhysicsJointWeld не является подтипом / подклассом SKPhysicsJointтак что актерский состав проваливается.

Вы можете обойти эту проблему, избегая приведения к [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
}

Это вернет вам немного "типа безопасности" времени компиляции, так как после этого компилятору потребуется все, что вы делаете с skJoint быть совместимым с SKPhysicsJoint, но это по-прежнему небезопасно в том смысле, что зависит от некоторых размахиваний руками вокруг типов времени выполнения, которые могут не всегда выполняться. И ты должен unsafeBitCast снова, чтобы добраться до определенного совместного подкласса, не зная, каким подклассом это может быть. (Опять же, сейчас самое время подать ошибку.)


(Вы можете заметить, что при вставке на игровую площадку physicsWorld также имеет внутренний класс: PKPhysicsWorld, Так почему же это не сработает? Когда вы используете physicsWorld Свойство, все приведение типов происходит на стороне ObjC, и Swift доверяет всему, что ObjC сообщает. Когда вы имеете дело с joints массив, однако, вы должны выполнить приведение типов на стороне Swift, и Swift гораздо более строг в проверке типов.)

Другие вопросы по тегам