Swift:无法将AnyObject向下转换为SKPhysicsBody

时间:2014-07-28 20:57:38

标签: ios arrays casting swift sprite-kit

Apple在SKPhysicsBody类中有以下方法。

 /* Returns an array of all SKPhysicsBodies currently in contact with this one */
    func allContactedBodies() -> [AnyObject]!

我注意到它返回一个AnyObject数组。所以我读到了如何处理向下转换AnyObject Here

我想循环遍历物理主体的allContactedBodies数组。问题是,无论我尝试什么,我都无法让事情发挥作用。

我先试了这个:

for body in self.physicsBody.allContactedBodies() as [SKPhysicsBody] {

}

但是我收到了这个错误。

  

致命错误:数组无法向下转换为派生数组

我也试过这个:

for object in self.physicsBody.allContactedBodies()  {
    let body = object as SKPhysicsBody
}

但是这也会崩溃:

enter image description here

同样地我尝试了这个:

 for object in self.physicsBody.allContactedBodies()  {
     let body = object as? SKPhysicsBody

 }

没有崩溃,但“身体”变成零。

如果我根本不投,我不会崩溃。例如:

for object in self.physicsBody.allContactedBodies()  {

}

但是,如果我想使用实际类型,我显然需要强制转换。


那么作为测试,我只是尝试了这个:

let object: AnyObject = SKPhysicsBody()
let body = object as SKPhysicsBody

这也会导致图片中出现同样的崩溃。


但其他类型不会崩溃。例如,这不会崩溃。

let object: AnyObject = SKNode()
let node = object as SKNode

所以我的问题是,如何才能正确遍历allContactedBodies数组?

编辑:我在iOS 8 beta 4设备上运行Xcode 6 beta 4.

编辑2:更多信息

好的,我只是做了一些测试。我试过这个:

let bodies = self.physicsBody.allContactedBodies() as? [SKPhysicsBody]

如果“allContactedBodies”为空,则转换成功。但是如果“allContactedBodies”包含对象,则转换失败并且“body”将变为nil,因此我无法遍历它。似乎目前将AnyObject强制转换为SKPhysicsBody是不可能的,因此无法循环遍历“allContactedBodies”数组,除非有人可以提供解决方法。

编辑3:Bug仍然在Xcode 6 beta 5中。下面的解决方法仍然有效 编辑4:Bug仍然在Xcode 6 beta 6.下面的解决方法仍然有效 编辑5:失望。 Bug仍在Xcode 6 GM中。下面发布的解决方法仍然有效

编辑6:我收到了Apple的以下消息:

  

工程部提供了以下信息:

     

我们认为此问题已在最新的Xcode 6.1测试版中得到解决。

但不是,错误仍在Xcode 6.1.1中!解决方法仍然有效。

编辑7: Xcode 6.3,仍然没有修复,解决方法仍然有效。

2 个答案:

答案 0 :(得分:7)

经过多次试验和错误,我找到了一个解决方法来解决我的问题。事实证明,当类型为AnyObject时,您根本不需要向下转换来访问SKPhysicsBody的属性。

for object in self.physicsBody.allContactedBodies()  {
        if object.node??.name == "surface" {
            isOnSurface = true
        }
    }

答案 1 :(得分:5)

更新:这是一个错误,它已在iOS 9 / OS X 10.11中修复。像下面这样的代码现在应该正常工作:

for body in self.physicsBody.allContactedBodies()  {
    // inferred type body: SKPhysicsBody
    print(body.node) // call an API defined on SKPhysicsBody
}

使用较旧的SDK /等为后代/伙伴留下原始答案文本。


在回答this one时,我在相关问题边栏中注意到了这一点,结果证明是相同的潜在问题。那么,虽然Epic Byte has a workable workaround,这是问题的根源,为什么解决方法有效,还有一些更多的解决方法......

这并不是说你不能将AnyObject强制转换为SKPhysicsBody - 而是隐藏在这些特定AnyObject引用后面的东西不能转换为{{ 1}}。

SKPhysicsBody返回的数组实际上包含allContactedBodies()个对象,而不是PKPhysicsBody个对象。 SKPhysicsBody不是公共API - 据推测,它应该是您看不到的实现细节。在ObjC中,只要你只调用两个类碰巧共享的方法,就可以将PKPhysicsBody强制转换为PKPhysicsBody * ...它只会“正常工作”。但是在Swift中,只能在类型层次结构中向上或向下使用SKPhysicsBody * / as / as?,而as!PKPhysicsBody不是父类和子类。

您收到错误广告SKPhysicsBody,因为即使let obj: AnyObject = SKPhysicsBody(); obj as SKPhysicsBody初始值设定项返回SKPhysicsBody。大多数时候你不需要经历这种舞蹈(并且让它失败),因为你从声称返回PKPhysicsBody的初始化器或方法中得到一个SKPhysicsBody - 所有在{1}}和SKPhysicsBody之间的手工波浪式铸造正在ObjC方面发生,Swift信任导入的ObjC API(并通过ObjC运行时调用回原始API,因此它的工作方式与尽管类型不匹配,但在ObjC中。

但是当你转换整个数组时,需要在Swift端进行运行时类型转换,因此Swift的更严格的类型检查规则发挥作用......将SKPhysicsBody实例转换为PKPhysicsBody失败那些规则,所以你崩溃了。您可以将空数组转换为PKPhysicsBody而不会出现错误,因为数组中没有任何冲突类型的对象(数组中没有任何对象)。

Epic Byte's workaround有效,因为Swift的SKPhysicsBody就像ObjC的[SKPhysicsBody]类型一样:编译器允许你调用任何类的方法,你只希望在运行时你正在处理实际实现这些方法的对象。

您可以通过明确强制侧面强制转换来获得一点编译时类型安全性:

AnyObject

在此之后,id是一个for object in self.physicsBody.allContactedBodies() { let body = unsafeBitCast(object, SKPhysicsBody.self) } ,因此编译器只允许你调用body方法...这就像ObjC强制转换一样,所以你还是留下了希望你调用的方法实际上是由你正在谈论的对象实现的。但至少编译器可以帮助你保持诚实。 (你不能SKPhysicsBody一个数组类型,所以你必须在循环内部对元素这样做。)

这应该被认为是一个错误,所以如果它影响到你,请let Apple know