Question

Apple propose la méthode suivante dans la classe SKPhysicsBody.

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

J'ai remarqué qu'il renvoie un tableau d'AnyObject.J'ai donc lu comment gérer la diffusion vers le bas d'AnyObject Ici

Je souhaite parcourir le tableau allContactedBodies de mon corps physique.Le problème est que peu importe ce que j’essaie, je n’arrive pas à faire fonctionner les choses.

J'ai d'abord essayé ceci :

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

}

Mais j'obtiens cette erreur.

erreur fatale:le tableau ne peut pas être réduit en tableau de dérivés

J'ai aussi essayé ceci :

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

Mais cela plante également avec ce qui suit :

enter image description here

Et de même j'ai essayé ceci :

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

 }

Il n’y a pas de crash, mais le « corps » devient nul.

Et si je ne lance aucun lancer, je n'ai pas de crash.Par exemple:

for object in self.physicsBody.allContactedBodies()  {

}

Mais évidemment, je dois lancer un casting si je veux utiliser le type réel.


Alors comme test, j'ai juste essayé ceci :

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

Et cela entraîne également le même crash que celui sur la photo.


Mais les autres types ne planteront pas.Par exemple, cela ne plantera pas.

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

Donc ma question est, comment puis-je parcourir correctement le tableau allContactedBodies?

Modifier:J'utilise Xcode 6 bêta 4 sur un appareil iOS 8 bêta 4.

Modifier 2 :Plus d'information

Ok, je viens de faire quelques tests supplémentaires.J'ai essayé ceci :

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

Si « allContactedBodies » est vide, alors la diffusion est réussie.Mais si "allContactedBodies" contient des objets, alors le casting échoue et "bodies" deviendra nul, donc je ne peux pas le parcourir en boucle.Il semble qu'actuellement, il n'est tout simplement PAS POSSIBLE de convertir AnyObject en SKPhysicsBody, ce qui rend impossible la boucle dans le tableau "allContactedBodies", à moins que quelqu'un puisse fournir une solution de contournement.

Modifier 3 :Bug toujours dans Xcode 6 beta 5.La solution de contournement publiée ci-dessous fonctionne toujours
Modifier 4 :Bug toujours dans Xcode 6 beta 6.La solution de contournement publiée ci-dessous fonctionne toujours
Modification 5 :Déçu.Bug toujours dans Xcode 6 GM.La solution de contournement publiée ci-dessous fonctionne toujours

MODIFICATION 6 :J'ai reçu le message suivant d'Apple :

L'ingénierie a fourni les informations suivantes :

Nous pensons que ce problème a été résolu dans la dernière version bêta de Xcode 6.1.

MAIS CE N'EST PAS le cas, le bug est toujours dans Xcode 6.1.1 !!!La solution de contournement fonctionne toujours.

Modification 7 : Xcode 6.3, toujours pas corrigé, la solution de contournement fonctionne toujours.

Était-ce utile?

La solution

Après beaucoup d'essais et d'erreurs, j'ai trouvé une solution de contournement à mon problème.Il s'avère que vous n'avez pas besoin de baisser du tout pour accéder aux propriétés du corps skphysicsique, lorsque le type est anyobject.

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

Autres conseils

Mise à jour:C'était un bug, et il a été corrigé dans iOS 9 / OS X 10.11.Un code comme celui-ci devrait fonctionner maintenant :

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

Laisser le texte de réponse original à la postérité/aux personnes utilisant des SDK plus anciens/etc.


J'ai remarqué cela dans la barre latérale des questions connexes en répondant celui-ci, et il s’avère que c’est le même problème sous-jacent.Donc pendant Epic Byte a une solution de contournement pratique, voici la racine du problème, pourquoi la solution de contournement fonctionne et quelques autres solutions de contournement...

Ce n'est pas que tu ne peux pas lancer de casting AnyObject à SKPhysicsBody en général — c'est que la ou les choses qui se cachent derrière ces AnyObject les références ne peuvent pas être converties SKPhysicsBody.

Le tableau renvoyé par allContactedBodies() contient en fait PKPhysicsBody des objets, pas SKPhysicsBody objets. PKPhysicsBody n'est pas une API publique - probablement, c'est censé être un détail d'implémentation que vous ne voyez pas.En ObjC, c'est vraiment cool de lancer un PKPhysicsBody * à SKPhysicsBody *...cela "fonctionnera" tant que vous n'appelez que les méthodes que les deux classes partagent.Mais dans Swift, vous pouvez diffuser avec as/as?/as! uniquement vers le haut ou vers le bas de la hiérarchie des types, et PKPhysicsBody et SKPhysicsBody ne sont pas une classe parent et une sous-classe.

Vous obtenez une erreur de casting let obj: AnyObject = SKPhysicsBody(); obj as SKPhysicsBody parce que même le SKPhysicsBody l'initialiseur renvoie un PKPhysicsBody.La plupart du temps, vous n'avez pas besoin de vous lancer dans cette danse (et de la faire échouer), car vous n'obtenez qu'un seul SKPhysicsBody retour d'un initialiseur ou d'une méthode qui prétend renvoyer un SKPhysicsBody — tout le casting ondulé à la main entre SKPhysicsBody et PKPhysicsBody se produit du côté ObjC, et Swift fait confiance à l'API ObjC importée (et rappelle l'API d'origine via le runtime ObjC, de sorte qu'elle fonctionne exactement comme elle le ferait dans ObjC malgré l'incompatibilité de type).

Mais lorsque vous lancez un tableau entier, un transtypage d'exécution doit avoir lieu du côté Swift, donc les règles de vérification de type plus strictes de Swift entrent en jeu...lancer un PKPhysicsBody exemple à SKPhysicsBody ne respecte pas ces règles, donc vous tombez en panne.Vous pouvez convertir un tableau vide en [SKPhysicsBody] sans erreur car il n'y a aucun objet de type conflictuel dans le tableau (il n'y a pas n'importe lequel objets dans le tableau).

Solution de contournement d'Epic Byte fonctionne parce que Swift AnyObject fonctionne comme celui d'ObjC id taper:le compilateur vous permet d'appeler des méthodes de n'importe quelle classe, et vous espérez simplement qu'au moment de l'exécution, vous avez affaire à un objet qui implémente réellement ces méthodes.

Vous pouvez récupérer un peu de sécurité de type au moment de la compilation en forçant explicitement un transtypage latéral :

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

Après ça, body est un SKPhysicsBody, le compilateur vous permettra donc d'appeler uniquement SKPhysicsBody méthodes là-dessus...cela se comporte comme un casting ObjC, vous devez donc toujours espérer que les méthodes que vous appelez sont réellement implémentées par l'objet auquel vous parlez.Mais au moins le compilateur peut vous aider à rester honnête.(Tu ne peux pas unsafeBitCast un type de tableau, vous devez donc le faire sur l'élément, à l'intérieur de la boucle.)

Cela devrait probablement être considéré comme un bug, alors s'il vous plaît faites le savoir à Apple si cela vous affecte.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top