1
votes

L'observateur didSet n'est pas appelé lors de l'initialisation de la propriété

Étant donné la classe suivante,

class Spaceship {

    var position: CGPoint! {
        didSet {
            node.position = position
        }
    }

    var node: SKSpriteNode!

    init(frame: CGRect) {

        node = SKSpriteNode(
            color: UIColor.red,
            size: CGSize(
                width: frame.size.width / 5,
                height: frame.size.width / 5
            )
        )

        self.position = CGPoint(x: frame.midX, y: frame.midY)

    } 

}

il semble que l'observateur didSet de la propriété position ne soit pas appelé.

Puisque l'observateur didSet devrait définir la position du nœud SpriteKit lorsque la propriété position est modifiée, j'ai pensé qu'au lieu d'utiliser la même ligne de code contenue dans le bloc didSet , je pourrais déclencher ce dernier à la place, mais cela ne semble pas fonctionner; lorsque la scène est créée (dans la GameScene principale, qui crée simplement un objet Spaceship et ajoute le spaceship.node au nœud enfants de la scène), le node semble être 0; 0 .

Avez-vous une idée de pourquoi cela se produit? Merci.

Mise à jour: bien que l'instruction différer fonctionne, l'attribution ne permet pas de l'utiliser.


4 commentaires

Copie possible de DidSet ne fonctionne pas dans la fonction init swift 3


Mise à jour de la question.


pourquoi ne sous-classez-vous pas le vaisseau spatial en tant que nœud de sprite?


@ Knight0fDragon J'y ai pensé mais je n'ai pas pu accéder aux propres propriétés de l'objet. Devraient-ils être annulés? Pouvez-vous également montrer comment le configureriez-vous? Merci!


3 Réponses :


1
votes

Les observateurs willSet et didSet des propriétés de superclasse sont appelés lorsqu'une propriété est définie dans un initialiseur de sous-classe, après l'appel de l'initialiseur de superclasse. Ils ne sont pas appelés lorsqu'une classe définit ses propres propriétés , avant que l'initialiseur de superclasse n'ait été appelé.

Une solution possible pourrait être de définir la propriété position en dehors de l'initialiseur du Spaceship , ou également de définir directement le nœud position.


2 commentaires

L'instruction " La propriété de position doit être définie en dehors de la classe Spaceship " est techniquement incorrecte. Il peut également être défini depuis Spaceship . Fondamentalement, didSet sera appelé à chaque fois que sa valeur est modifiée, mais pas dans init .


citation est ok , conclusion non. Quoi qu'il en soit, la réponse ne vaut pas mon vote.



3
votes

Plutôt que d'utiliser didSet pour mettre à jour votre nœud, transférez-lui directement les requêtes:

class Spaceship {

    let node: SKSpriteNode

    init(frame: CGRect) {
        self.node = SKSpriteNode(
            color: UIColor.red,
            size: CGSize(
                width: frame.size.width / 5,
                height: frame.size.width / 5
            )
        )

        self.position = CGPoint(x: frame.midX, y: frame.midY)
    }

    var position: CGPoint {
        get { return node.position }
        set { node.position = newValue }
    }
}


2 commentaires

Brillant! Cela fonctionne, mais le setter a besoin que la valeur soit assignée comme paramètre: set (newValue) {...} , sinon cela ne semble pas fonctionner; peut-être que le compilateur récupère l'ancienne valeur stockée et l'affecte à node.position . Est-ce le cas?


@Fehniix C'était un type de ma part. node.position = position serait équivalent à node.position = self.position , donc équivalent à node.position = node.position , donc ça ne fera rien. Vous pouvez ajouter un nom à la valeur, mais par défaut, c'est implicitement newValue , donc je l'ai juste changé pour l'utiliser



0
votes

Personnellement, je sous-classerais simplement le vaisseau spatial en tant que SKSpriteNode. Le vaisseau spatial ne semble pas être un objet complexe qui implique la composition plutôt que l'héritage.

class Spaceship : SKSpriteNode {
    convenience init(frame: CGRect) {
        self.init(
            color: UIColor.red,
            size: CGSize(
                width: frame.size.width / 5, 
                height: frame.size.width / 5
            )
        )
        self.position = CGPoint(x: frame.midX, y: frame.midY)
   } 
}

Maintenant, je ne sais pas pourquoi vous passez dans un cadre comme celui-ci ... Je suppose que le cadre est votre scène ? Si tel est le cas, vous allez rencontrer des problèmes lorsque le point d'ancrage n'est pas (0,0).


4 commentaires

J'ai choisi ce modèle pour pouvoir simplement instancier un objet Spaceship dans MainScene et ajouter le nœud enfant; au lieu de colmater MainScene avec des milliers de lignes de code, je préférerais adopter ce modèle par souci de propreté. Proposeriez-vous un modèle différent pour obtenir ce résultat? Merci.


Ce que vous avez dit n'a rien à voir avec ce que je demande. Je ne vois pas le but de passer dans le cadre. Le cadre est-il la taille de votre scène? En règle générale, vous ne souhaitez concevoir qu'une seule taille de scène


Pardon. Oui, c'est la taille du cadre.


Votre objectif est-il que le vaisseau spatial commence au centre de la scène? Y a-t-il une raison pour laquelle le point d'ancrage de votre scène n'est pas 0,5 0,5 autre que vous avez peut-être regardé un mauvais tutoriel