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这是相同的基础问题。 所以,虽然史诗字节有一个可行的解决方法 ,这里是问题的根源,为什么解决方法工作,和一些更多的解决方法…
这并不是说你无法将AnyObject
为SKPhysicsBody
,而是隐藏在这些特定的AnyObject
引用之后的东西不能转换为SKPhysicsBody
。
由allContactedBodies()
返回的数组实际上包含PKPhysicsBody
对象,而不是SKPhysicsBody
对象。 PKPhysicsBody
不是公共API – 大概它应该是一个你看不到的实现细节。 在ObjC中,将PKPhysicsBody *
投射到SKPhysicsBody *
是非常酷的……只要你只调用两个类共享的方法,它就会“正常工作”。 但是在Swift中,你可以使用as
/ as?
/ as!
只能向上或向下的types层次结构,而PKPhysicsBody
和SKPhysicsBody
不是父类和子类。
你得到一个错误转换let obj: AnyObject = SKPhysicsBody(); obj as SKPhysicsBody
let obj: AnyObject = SKPhysicsBody(); obj as SKPhysicsBody
因为即使SKPhysicsBody
初始化器也返回一个PKPhysicsBody
。 大多数时候你不需要经过这个舞蹈(并且失败),因为你从一个声称返回一个SKPhysicsBody
的初始化方法或方法中得到一个单一的SKPhysicsBody
– 所有的SKPhysicsBody
和PKPhysicsBody
发生在ObjC端,而Swift信任导入的ObjC API(并通过ObjC运行时调用回原始API,所以它的工作方式与ObjC中尽pipetypes不匹配一样)。
但是当你投射整个数组时,Swift需要在Swift端发生,所以Swift的更严格的types检查规则开始发挥作用…将一个PKPhysicsBody
实例投射到SKPhysicsBody
失败这些规则,所以你会崩溃。 您可以将一个空数组[SKPhysicsBody]
为[SKPhysicsBody]
,因为在数组中没有任何冲突types的对象(数组中没有任何对象)。
Epic Byte的解决方法是AnyObject
因为Swift的AnyObject
像ObjC的id
types一样工作:编译器可以让你调用任何类的方法,而且你只是希望在运行时处理一个实际实现这些方法的对象。
你可以通过明确地强制一个侧演来恢复一些编译时types的安全性:
for object in self.physicsBody.allContactedBodies() { let body = unsafeBitCast(object, SKPhysicsBody.self) }
在这之后, body
是一个SKPhysicsBody
,所以编译器会让你只调用SKPhysicsBody
方法…这就像ObjC casting,所以你仍然希望你调用的方法实际上是由你所对象实现的和……说话。 但至less编译器可以帮助你保持诚实。 (你不能unsafeBitCast
一个数组types,所以你必须做到这一点,循环内的元素。)
这可能应该被认为是一个错误,所以请让苹果知道,如果它影响你。