0
votes

The following code results to class cast exception. Could someone explain me why?

var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
firstBody = contact.bodyA
secondBody = contact.bodyB
projectileDidCollide(firstBody.node as SKSpriteNode, flyingLabel: secondBody.node as SKLabelNode)

results in ClassCastException:

libswiftCore.dylib`swift_dynamicCastObjCClassUnconditional: 0x104668980: pushq %rbp 0x104668981: movq %rsp, %rbp 0x104668984: pushq %rbx 0x104668985: pushq %rax 0x104668986: movq %rsi, %rcx 0x104668989: movq %rdi, %rbx 0x10466898c: xorl %eax, %eax 0x10466898e: testq %rbx, %rbx 0x104668991: je 0x1046689ac ; swift_dynamicCastObjCClassUnconditional + 44 0x104668993: movq 0x7f236(%rip), %rsi ; "isKindOfClass:" 0x10466899a: movq %rbx, %rdi 0x10466899d: movq %rcx, %rdx 0x1046689a0: callq 0x10466b46a ; symbol stub for: objc_msgSend 0x1046689a5: testb %al, %al 0x1046689a7: movq %rbx, %rax 0x1046689aa: je 0x1046689b3 ; swift_dynamicCastObjCClassUnconditional + 51 0x1046689ac: addq $0x8, %rsp 0x1046689b0: popq %rbx 0x1046689b1: popq %rbp 0x1046689b2: retq
0x1046689b3: leaq 0xc158(%rip), %rax ; "Swift dynamic cast failed" 0x1046689ba: movq %rax, 0x87427(%rip) ; gCRAnnotations + 8 0x1046689c1: int3
0x1046689c2: nopw %cs:(%rax,%rax)

1
You haven't set firstBody and secondBody to anything. Why do you need to cast firstBody.node and secondBody.node into SKSpriteNote and SKLabelNode, respectively? - DrOverbuild
I'm doing additional processing in another method such as: projectile.removeFromParent() flyingLabel.removeFromParent() - user3673836
There's no guarantee that the nodes will be in that order in the collision delegate method (assuming that's where this is). firstBody.node might be the SKLabelNode and secondBody.node might be the SKSpriteNode. - Mike S
That sorts it out. Thank you! - user3673836

1 Answers

1
votes

You don't know which body is which in your contact handler โ€” for any given contact, SpriteKit labels the two bodies bodyA and bodyB in arbitrary order. Even if your contact bit masks are set up so that all collisions are between a sprite and a label, bodyA may be the sprite on one collision and the label on another.

Your contact handler should account for this. Check either possible order of bodies before handing off to code that needs to know the type of each. You can do this by conditional casting with as? or (to be more generally useful in games with more kinds of collisions) checking the categoryBitMask of each body.