J'apprends le développement iOS à partir d'un cours en ligne et chaque fois que je crée une vue personnalisée (cellule de vue de tableau personnalisée, cellule de vue de collection, etc.), l'instructeur implémente toujours cet initialiseur:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Pourquoi exactement dois-je toujours appeler ça? Qu'est ce que ça fait? Puis-je mettre des propriétés dans l'init?
NSCoding
vous devez implémenter cet initialiseur, car il est requis pour les classes qui implémententNSCoding
. Vous devez au moins appeler la méthode d'initialisation de la superclasse. Si leNSCoder
contient des propriétés encodées pour votre classe, vous pouvez utiliser cette méthode pour les récupérerRéponses:
Je vais commencer cette réponse dans la direction opposée: que faire si vous souhaitez enregistrer l'état de votre vue sur le disque? C'est ce qu'on appelle la sérialisation . L'inverse est la désérialisation - la restauration de l'état de l'objet à partir du disque.
Le
NSCoding
protocole définit deux méthodes pour sérialiser et désérialiser des objets:Alors pourquoi est-il nécessaire dans votre classe personnalisée? La réponse est 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. À tout le moins, si vous n'ajoutez aucune nouvelle propriété à votre sous-classe, vous pouvez simplement demander à la superclasse de faire l'emballage et le déballage pour vous, d'où l'
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.
la source
init(coder aCoder : NSCoder)
?awakeFromNib
ne fonctionnera pas.awakeFromNib
est appelée au moment de l'exécution . Tout ce que vous faites dans Interface Builder est au moment de la conception . Pour transporter ce que vous avez fait au moment de la conception au temps d' exécution, il fautencodeWithCoder
(enregistrer) etinit(coder:)
(charger)awakeFromNib
ouinitWIthFrame
La nécessité d'implémenter cet initialiseur est une conséquence de deux choses:
Le principe de substitution de Liskov . Si S est une sous-classe de T (par exemple
MyViewController
est une sous-classe deViewController
), alors les objets S (instances deMyViewController
) doivent pouvoir être substitués là où T objets (instances deViewController
) sont attendus.Les initialiseurs ne sont pas hérités dans Swift si des initialiseurs sont explicitement définis dans la sous-classe. Si un initialiseur est explicitement fourni, alors tous les autres doivent être explicitement fournis (qui peuvent alors simplement appeler
super.init(...)
). Voir cette question pour la justification. C'est en Java, mais s'applique toujours.Au point 1, tout ce que l'original
ViewController
peut faire, laMyViewController
sous - classe devrait pouvoir le faire. Une telle chose est de pouvoir être initialisé à partir d'une donnéeNSCoder
. Au point 2, votreMyViewController
sous-classe n'hérite pas automatiquement de cette capacité. Ainsi, vous devez fournir manuellement l'initialiseur qui remplit cette condition. Dans ce cas, il vous suffit de déléguer jusqu'à la superclasse, pour qu'elle fasse ce qu'elle ferait habituellement.la source