136 votes

Qu'est-ce qu'un init coder aDecoder ?

J'apprends le développement iOS dans le cadre d'un cours en ligne et chaque fois que je crée une vue personnalisée (cellule de vue de table personnalisée, cellule de vue de collection, etc.), l'instructeur met toujours en œuvre cet initialisateur :

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

Pourquoi est-ce que je dois toujours appeler ça ? Que fait-il ? Puis-je mettre des propriétés dans l'init ?

5 votes

Cette réponse vous aidera stackoverflow.com/questions/24036393/ Merci.

2 votes

Si vous sous-classez un objet qui implémente la fonction NSCoding alors vous devez implémenter cet initialisateur, puisqu'il est requis pour les classes qui implémentent la fonction NSCoding . Vous devez au moins appeler la méthode init de la superclasse. Si la méthode NSCoder contient des propriétés codées pour votre classe, vous pouvez utiliser cette méthode pour récupérer ces propriétés.

134voto

Zoff Dino Points 5010

Je vais commencer cette réponse par la direction opposée : que faire si vous voulez sauvegarder l'état de votre vue sur le disque ? C'est ce qu'on appelle sérialisation . L'inverse est désérialisation - restauration de l'état de l'objet à partir du disque.

El NSCoding définit deux méthodes pour sérialiser et désérialiser les objets :

encodeWithCoder(_ aCoder: NSCoder) {
    // Serialize your object here
}

init(coder aDecoder: NSCoder) {
    // Deserialize your object here
}

Alors pourquoi est-il nécessaire dans votre classe personnalisée ? La réponse est l'Interface Builder. Lorsque vous faites glisser un objet sur un storyboard et le configurez, Interface Builder sérialise l'état de cet objet sur le disque, puis le désérialise lorsque le storyboard apparaît à l'écran. Vous devez indiquer à Interface Builder comment procéder. Au minimum, si vous n'ajoutez pas de nouvelles propriétés à votre sous-classe, vous pouvez simplement demander à la super-classe de faire l'emballage et le déballage pour vous, d'où l'utilisation de l'option super.init(coder: aDecoder) appel. Si votre sous-classe est plus complexe, vous devez ajouter votre propre code de sérialisation et de désérialisation pour la sous-classe.

Cela contraste avec l'approche de Visual Studio, qui consiste à écrire du code dans un fichier caché pour créer l'objet au moment de l'exécution.

0 votes

Pourquoi ne pas tout mettre dans awakeFromNib et oublier l'utilisation de init(coder aCoder : NSCoder) ?

0 votes

@Honey - en un mot, "parfois vous ne pouvez pas faire ça". Vous pouvez généralement le faire, mais pas toujours.

1 votes

@Fattie les détails pour ne pas le faire sont-ils trop complexes ou inutiles à connaître ? Si ce n'est pas le cas, pouvez-vous les expliquer ?

31voto

XAleXOwnZX Points 159

La nécessité de mettre en œuvre cet initialisateur est la conséquence de deux choses :

  1. El Principe de substitution de Liskov . Si S est une sous-classe de T (par ex. MyViewController est une sous-classe de ViewController ), alors les objets S (instances de MyViewController ) doivent pouvoir être remplacés par des objets T (instances de ViewController ) sont attendus.

  2. Les initialisateurs ne sont pas hérités dans Swift si des initialisateurs sont explicitement définis dans la sous-classe. Si un initialisateur est explicitement fourni, alors tous les autres doivent être explicitement fournis (qui peuvent alors juste appeler super.init(...) ). Voir cette question pour le raisonnement. C'est en Java, mais ça reste valable.

Par le point 1, tout ce que l'original ViewController peut faire, le MyViewController La sous-classe devrait pouvoir le faire. L'une d'entre elles est de pouvoir être initialisée à partir d'une classe donnée. NSCoder . Au point 2, votre MyViewController n'hérite pas automatiquement de cette capacité. Vous devez donc fournir manuellement l'initialisateur qui répond à cette exigence. Dans ce cas, il suffit de déléguer à la superclasse pour qu'elle fasse ce qu'elle ferait normalement.

1 votes

Il est parfaitement logique que les constructeurs ne soient pas hérités : Si vous initialisez une instance de la classe dérivée en utilisant l'initialisateur (hérité) de la classe de base, les propriétés non héritées qui ont été nouvellement définies ("ajoutées") par la classe dérivée ne seront jamais initialisées.

3 votes

En fait, les initialisateurs sont hérités en Swift, étant donné que vous ne fournissez aucune de vos propres implémentations d'initialisateurs dans votre sous-classe. Si vos propriétés non héritées nouvellement définies ont des valeurs par défaut, vous pouvez vous en sortir en n'écrivant aucun initialisateur dans votre sous-classe et en héritant simplement de tous les initialisateurs de votre super-classe. Voir aquí

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X