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

苹果在SKPhysicsBody类中有以下方法。

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

我注意到它返回一个AnyObject的数组。 所以我读了关于如何处理在这里下载 AnyObject

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

我先试了一下:

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

但是我得到这个错误。

致命错误:数组不能倒数到派生的数组

我也试过这个:

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

但是,这也崩溃了以下内容:

在这里输入图像说明

同样我也试过这个:

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

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

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

 for object in self.physicsBody.allContactedBodies() { } 

但是,如果我想使用实际的types,显然我需要投。

那么作为一个testing,我只是试过这个:

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

这也导致了图片中的相同的崩溃。

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

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

所以我的问题是, 我怎样才能正确循环通过allContactedBodies数组

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

编辑2:更多信息

好吧,我只是做了更多的testing。 我试过这个:

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

如果“allContactedBodies”为空,则表示成功。 但是,如果“allContactedBodies”包含对象,则投射失败,“body”将变为零,所以我无法循环。 现在看来,将AnyObject强制转换为SKPhysicsBody是不可能的,除非有人可以提供解决方法,否则无法遍历“allContactedBodies”数组。

编辑3:错误仍然在Xcode 6testing版5.下面发布的解决方法仍然有效
编辑4:错误仍然在Xcode 6testing版6.下面发布的解决方法仍然有效
编辑5:失望。 错误仍然在Xcode 6 GM。 下面发布的解决方法仍然有效

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

Engineering提供了以下信息:

我们相信这个问题已经在最新的Xcode 6.1 beta中得到了解决。

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

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

经过多次的反复试验,我发现了一个解决方法解决我的问题。 事实certificate,当types为AnyObject时,您根本不需要downcast来访问SKPhysicsBody的属性。

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

更新:这是一个错误,它已在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 /离开留给后人/人的原始答案文本


我在回答这个问题的时候在相关的问题边栏中注意到了这一点 ,事实certificate这是相同的基础问题。 所以,虽然史诗字节有一个可行的解决方法 ,这里是问题的根源,为什么解决方法工作,和一些更多的解决方法…

这并不是说你无法将AnyObjectSKPhysicsBody ,而是隐藏在这些特定的AnyObject引用之后的东西不能转换为SKPhysicsBody

allContactedBodies()返回的数组实际上包含PKPhysicsBody对象,而不是SKPhysicsBody对象。 PKPhysicsBody不是公共API – 大概它应该是一个你看不到的实现细节。 在ObjC中,将PKPhysicsBody *投射到SKPhysicsBody *是非常酷的……只要你只调用两个类共享的方法,它就会“正常工作”。 但是在Swift中,你可以使用as / as? / as! 只能向上或向下的types层次结构,而PKPhysicsBodySKPhysicsBody不是父类和子类。

你得到一个错误转换let obj: AnyObject = SKPhysicsBody(); obj as SKPhysicsBody let obj: AnyObject = SKPhysicsBody(); obj as SKPhysicsBody因为即使SKPhysicsBody初始化器也返回一个PKPhysicsBody 。 大多数时候你不需要经过这个舞蹈(并且失败),因为你从一个声称返回一个SKPhysicsBody的初始化方法或方法中得到一个单一的SKPhysicsBody – 所有的SKPhysicsBodyPKPhysicsBody发生在ObjC端,而Swift信任导入的ObjC API(并通过ObjC运行时调用回原始API,所以它的工作方式与ObjC中尽pipetypes不匹配一样)。

但是当你投射整个数组时,Swift需要在Swift端发生,所以Swift的更严格的types检查规则开始发挥作用…将一个PKPhysicsBody实例投射到SKPhysicsBody失败这些规则,所以你会崩溃。 您可以将一个空数组[SKPhysicsBody][SKPhysicsBody] ,因为在数组中没有任何冲突types的对象(数组中没有任何对象)。

Epic Byte的解决方法是AnyObject因为Swift的AnyObject像ObjC的idtypes一样工作:编译器可以让你调用任何类的方法,而且你只是希望在运行时处理一个实际实现这些方法的对象。

你可以通过明确地强制一个侧演来恢复一些编译时types的安全性:

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

在这之后, body是一个SKPhysicsBody ,所以编译器会让你只调用SKPhysicsBody方法…这就像ObjC casting,所以你仍然希望你调用的方法实际上是由你所对象实现的和……说话。 但至less编译器可以帮助你保持诚实。 (你不能unsafeBitCast一个数组types,所以你必须做到这一点,循环内的元素。)

这可能应该被认为是一个错误,所以请让苹果知道,如果它影响你。