SKPhysicsBody自定义扩展新方法失效:抛出“PKPhysicsBody无法识别选择器”错误
解决SKPhysicsBody扩展失效:PKPhysicsBody unrecognized selector错误
这个问题我之前在做ARKit结合SpriteKit的项目时碰到过,踩过不少坑!核心原因其实很简单:你当前调用扩展方法的物理体实例,根本不是SKPhysicsBody,而是苹果SpriteKit内部使用的私有子类PKPhysicsBody。
为什么会出现这个错误?
Swift扩展默认是静态派发的,而SKPhysicsBody是Objective-C实现的框架类。当SpriteKit在某些场景(比如ARKit的ARSKView中)把物理体替换成PKPhysicsBody时,这个私有子类无法继承你给SKPhysicsBody写的Swift扩展方法,所以会抛出“unrecognized selector”的错误。
推荐的解决方法
1. 给扩展添加@objc标记,支持动态派发
把你的扩展改成Objective-C兼容的形式,这样作为SKPhysicsBody子类的PKPhysicsBody就能继承这些方法了,这是最稳妥的方案:
首先确保你的PhysicsCategory枚举是@objc兼容的:
import SpriteKit @objc enum PhysicsCategory: Int { case player case enemy // 你的其他物理分类... }
然后修改扩展,给每个方法加上@objc:
extension SKPhysicsBody { @objc func hasCategory(_ searchedCategory: PhysicsCategory) -> Bool { let haystack = categoryBitMask let needle = searchedCategory.rawValue return haystack & needle == needle } @objc func addCollisionWithCategory(_ category: PhysicsCategory) { collisionBitMask |= category.rawValue } @objc func addContactingWithCategory(_ category: PhysicsCategory) { contactTestBitMask |= category.rawValue } }
这样修改后,无论是SKPhysicsBody还是PKPhysicsBody实例,都能正常调用这些方法了。
2. 显式检查物理体类型(适合仅需处理SKPhysicsBody的场景)
如果你只希望对SKPhysicsBody实例执行操作,可以在调用前做类型检查,避免对PKPhysicsBody调用方法:
// 示例:在节点上操作物理体时 if let validBody = node.physicsBody as? SKPhysicsBody { validBody.addContactingWithCategory(.player) } else { // 可选:打印日志排查问题 print("注意:当前物理体不是SKPhysicsBody,实际类型是\(type(of: node.physicsBody))") }
3. 直接给PKPhysicsBody加扩展(不推荐)
虽然可以给私有类PKPhysicsBody复制一份相同的扩展,但这种方式依赖苹果的私有API,随时可能因为框架更新失效,还有App Store审核不通过的风险,所以尽量不要用。
内容的提问来源于stack exchange,提问作者Yaroslav Yaremenko
相关产品推荐
相关产品推荐

