Swift SKPhysicsBody 的便捷初始化程序扩展

Swift convenience initializer extension for SKPhysicsBody

extension SKPhysicsBody {

    /// anchorPoint version of init(rectangleOfSize:center:)
    convenience init(rectangleOfSize s: CGSize, withAnchorPoint anchorPoint: CGPoint) {
        var center = CGPoint()
        center.x = (s.width / 2) - ( s.width * anchorPoint.x)
        center.y = (s.height / 2 ) - ( s.height * anchorPoint.y)
        self.init(rectangleOfSize: s, center: center)
    }

}

我在运行时遇到了这个错误

-[PKPhysicsBody initWithRectangleOfSize:withAnchorPoint:]: unrecognized selector sent to instance 0x7f9b03c4fff0

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PKPhysicsBody initWithRectangleOfSize:withAnchorPoint:]: unrecognized selector sent to instance 0x7f9b03c4fff0'

这是我在代码中调用的方式

// redBox is a typical SKSpriteNode()
redBox.physicsBody = SKPhysicsBody(rectangleOfSize: redBox.frame.size, withAnchorPoint: redBox.anchorPoint)

我基本上想扩展 SKPhysicsBody class 为其工厂方法提供便利的初始值设定项

正如@Cristik 在评论中猜测的那样,这是与 and this question 相同的根本问题:public SKPhysicsBody class 是私有 PKPhysicsBody class 提供其实现。

过去,这种方法严重依赖 Objective-C 的 "duck typing" 行为 — 只要 ClassA 响应与 ClassB 相同的所有选择器,您可以在静态类型(在源代码中向编译器声明的类型)为 ClassB 的指针上调用任何这些选择器,即使在 运行 时间的实际对象实际上是 [=12] 的实例=].

Swift 在 运行 时间类型正确性方面比 ObjC 更严格,因此仅 "duck typing" 是不够的。从 iOS 9 / OS X 10.11 开始,SpriteKit 有一些变通方法允许 PKPhysicsBody 个实例更好地伪装成 SKPhysicsBody 个实例。

但是这些并没有涵盖所有情况——特别是,它没有捕捉到 (ObjC) [SKPhysicsBody alloc] 返回一个 PKPhysicsBody 实例,这意味着任何向 [=10 添加初始值设定项的尝试=] 在 Swift 中将失败。 (因为 ObjC alloc/init 进程在 Swift 中减少为一次初始化程序调用。)

我认为这是一个错误并推荐 filing it with Apple


Edit/update:在该错误得到修复之前(已经一年多了),解决方法是将您的便利 "initializer" 改为 class 方法。 (如果必须的话,或者一个全局函数,但是...... ewww。)