Schnell:AnyObject kann nicht auf SKPhysicsBody heruntergestuft werden
-
20-12-2019 - |
Frage
Apple verfügt über die folgende Methode in der SKPhysicsBody-Klasse.
/* Returns an array of all SKPhysicsBodies currently in contact with this one */
func allContactedBodies() -> [AnyObject]!
Mir ist aufgefallen, dass es ein Array von AnyObject zurückgibt.Also habe ich gelesen, wie man mit dem Downcasting von AnyObject umgeht Hier
Ich möchte das Array allContactedBodies meines Physikkörpers durchlaufen.Das Problem ist, egal was ich versuche, ich schaffe es einfach nicht, etwas zum Laufen zu bringen.
Ich habe es als erstes versucht:
for body in self.physicsBody.allContactedBodies() as [SKPhysicsBody] {
}
Aber ich bekomme diesen Fehler.
fataler Fehler:Das Array kann nicht auf ein abgeleitetes Array heruntergestuft werden
Ich habe auch Folgendes versucht:
for object in self.physicsBody.allContactedBodies() {
let body = object as SKPhysicsBody
}
Dies stürzt aber auch mit Folgendem ab:
Und ähnlich habe ich Folgendes versucht:
for object in self.physicsBody.allContactedBodies() {
let body = object as? SKPhysicsBody
}
Es gibt keinen Absturz, aber „Körper“ wird zu Null.
Und wenn ich überhaupt nicht wirke, bekomme ich keinen Absturz.Zum Beispiel:
for object in self.physicsBody.allContactedBodies() {
}
Aber natürlich muss ich umwandeln, wenn ich den tatsächlichen Typ verwenden möchte.
Als Test habe ich dann einfach Folgendes ausprobiert:
let object: AnyObject = SKPhysicsBody()
let body = object as SKPhysicsBody
Und dies führt auch zu dem gleichen Absturz, der auf dem Bild zu sehen ist.
Aber andere Typen werden nicht abstürzen.Dies wird beispielsweise nicht abstürzen.
let object: AnyObject = SKNode()
let node = object as SKNode
Meine Frage ist also: Wie kann ich das Array allContactedBodies korrekt durchlaufen??
Bearbeiten:Ich verwende Xcode 6 Beta 4 auf einem iOS 8 Beta 4-Gerät.
Bearbeiten 2:Mehr Informationen
Ok, also habe ich einfach noch ein paar Tests gemacht.Ich habe Folgendes versucht:
let bodies = self.physicsBody.allContactedBodies() as? [SKPhysicsBody]
Wenn „allContactedBodies“ leer ist, ist die Umwandlung erfolgreich.Aber wenn „allContactedBodies“ Objekte enthält, schlägt die Umwandlung fehl und „bodies“ wird zu Null, sodass ich sie nicht durchlaufen kann.Es scheint, dass es derzeit einfach NICHT MÖGLICH ist, AnyObject in SKPhysicsBody umzuwandeln, was es unmöglich macht, das Array „allContactedBodies“ zu durchlaufen, es sei denn, jemand kann eine Problemumgehung bereitstellen.
Bearbeiten 3:Fehler immer noch in Xcode 6 Beta 5.Die unten angegebene Problemumgehung funktioniert weiterhin
Bearbeiten 4:Fehler immer noch in Xcode 6 Beta 6.Die unten angegebene Problemumgehung funktioniert weiterhin
Bearbeiten 5:Enttäuscht.Fehler immer noch in Xcode 6 GM.Die unten angegebene Problemumgehung funktioniert weiterhin
EDIT 6:Ich habe die folgende Nachricht von Apple erhalten:
Engineering hat die folgenden Informationen bereitgestellt:
Wir glauben, dass dieses Problem in der neuesten Betaversion von Xcode 6.1 behoben wurde.
ABER DAS IST ES NICHT, der Fehler ist immer noch in Xcode 6.1.1!!!Die Problemumgehung funktioniert immer noch.
Bearbeiten 7: Xcode 6.3, immer noch nicht behoben, Problemumgehung funktioniert immer noch.
Lösung
Nach viel Prozess und Irrtum habe ich ein
Andere Tipps
Aktualisieren:Dies war ein Fehler und wurde in iOS 9 / OS X 10.11 behoben.Code wie der folgende sollte jetzt funktionieren:
for body in self.physicsBody.allContactedBodies() {
// inferred type body: SKPhysicsBody
print(body.node) // call an API defined on SKPhysicsBody
}
Hinterlassen des ursprünglichen Antworttextes für die Nachwelt / für Leute, die ältere SDKs verwenden / usw.
Das ist mir bei der Beantwortung in der Seitenleiste mit den entsprechenden Fragen aufgefallen Dieses hier, und es stellt sich heraus, dass es sich um dasselbe zugrunde liegende Problem handelt.Also, während Epic Byte hat einen praktikablen Workaround, hier ist die Ursache des Problems, warum die Problemumgehung funktioniert und einige weitere Problemumgehungen ...
Es ist nicht so, dass man nicht wirken kann AnyObject
Zu SKPhysicsBody
im Allgemeinen – es ist das/die Ding(e), das/die sich hinter diesen besonderen Dingen verbirgt AnyObject
Verweise können nicht umgewandelt werden SKPhysicsBody
.
Das von zurückgegebene Array allContactedBodies()
tatsächlich enthält PKPhysicsBody
Objekte, nicht SKPhysicsBody
Objekte. PKPhysicsBody
ist keine öffentliche API – vermutlich handelt es sich um ein Implementierungsdetail, das Sie nicht sehen.In ObjC ist es total cool, einen zu wirken PKPhysicsBody *
Zu SKPhysicsBody *
...es wird „einfach funktionieren“, solange Sie nur Methoden aufrufen, die die beiden Klassen zufällig gemeinsam nutzen.Aber in Swift können Sie mit casten as
/as?
/as!
nur nach oben oder unten in der Typhierarchie und PKPhysicsBody
Und SKPhysicsBody
sind keine übergeordnete Klasse und Unterklasse.
Sie erhalten einen Casting-Fehler let obj: AnyObject = SKPhysicsBody(); obj as SKPhysicsBody
denn sogar die SKPhysicsBody
Initialisierer gibt a zurück PKPhysicsBody
.In den meisten Fällen ist es nicht nötig, diesen Tanz zu absolvieren (und scheitern zu lassen), denn man bekommt einen einzigen SKPhysicsBody
zurück von einem Initialisierer oder einer Methode, die behauptet, eine zurückzugeben SKPhysicsBody
– der ganze handgewellte Guss dazwischen SKPhysicsBody
Und PKPhysicsBody
geschieht auf der ObjC-Seite und Swift vertraut der importierten ObjC-API (und ruft über die ObjC-Laufzeit die ursprüngliche API zurück, sodass es trotz der Typinkongruenz genauso funktioniert wie in ObjC).
Wenn Sie jedoch ein ganzes Array umwandeln, muss auf der Swift-Seite eine Laufzeittypumwandlung erfolgen, sodass die strengeren Typprüfungsregeln von Swift ins Spiel kommen ...Casting a PKPhysicsBody
Instanz zu SKPhysicsBody
verstößt gegen diese Regeln, sodass Sie abstürzen.Sie können ein leeres Array umwandeln [SKPhysicsBody]
ohne Fehler, da das Array keine Objekte widersprüchlichen Typs enthält (es gibt keine). beliebig Objekte im Array).
Problemumgehung von Epic Byte funktioniert, weil Swift's AnyObject
Funktioniert wie ObjCs id
Typ:Mit dem Compiler können Sie Methoden jeder beliebigen Klasse aufrufen und hoffen, dass Sie es zur Laufzeit mit einem Objekt zu tun haben, das diese Methoden tatsächlich implementiert.
Sie können ein wenig Typsicherheit zur Kompilierungszeit wiederherstellen, indem Sie explizit eine Seitenumwandlung erzwingen:
for object in self.physicsBody.allContactedBodies() {
let body = unsafeBitCast(object, SKPhysicsBody.self)
}
Danach, body
ist ein SKPhysicsBody
, sodass der Compiler nur Sie aufrufen lässt SKPhysicsBody
Methoden dazu...Dies verhält sich wie ein ObjC-Casting, sodass Sie immer noch hoffen müssen, dass die von Ihnen aufgerufenen Methoden tatsächlich von dem Objekt implementiert werden, mit dem Sie sprechen.Aber zumindest kann der Compiler dabei helfen, ehrlich zu bleiben.(Das kannst du nicht unsafeBitCast
ein Array-Typ, daher müssen Sie dies mit dem Element innerhalb der Schleife tun.)
Dies sollte wahrscheinlich als Fehler betrachtet werden, also bitte lass es Apple wissen wenn es Sie betrifft.