Ich lerne die iOS-Entwicklung aus einem Online-Kurs und jedes Mal, wenn ich eine benutzerdefinierte Ansicht erstelle (benutzerdefinierte Tabellenansichtszelle, Sammlungsansichtszelle usw.), implementiert der Kursleiter diesen Initialisierer:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Warum genau muss ich das immer nennen? Was tut es? Kann ich Eigenschaften in den Init einfügen?
NSCoding
müssen Sie diesen Initialisierer implementieren, da er für implementierte Klassen erforderlich istNSCoding
. Sie müssen mindestens die Superclass-Init-Methode aufrufen. Wenn dasNSCoder
codierte Eigenschaften für Ihre Klasse enthält, können Sie diese Methode verwenden, um dieseAntworten:
Ich beginne diese Antwort aus der entgegengesetzten Richtung: Was ist, wenn Sie den Status Ihrer Ansicht auf der Festplatte speichern möchten? Dies wird als Serialisierung bezeichnet . Das Gegenteil ist die Deserialisierung , bei der der Status des Objekts von der Festplatte wiederhergestellt wird.
Das
NSCoding
Protokoll definiert zwei Methoden zum Serialisieren und Deserialisieren von Objekten:Warum wird es in Ihrer benutzerdefinierten Klasse benötigt? Die Antwort lautet Interface Builder. Wenn Sie ein Objekt auf ein Storyboard ziehen und konfigurieren, serialisiert Interface Builder den Status dieses Objekts auf der Festplatte und deserialisiert es dann, wenn das Storyboard auf dem Bildschirm angezeigt wird. Sie müssen Interface Builder mitteilen, wie dies zu tun ist. Wenn Sie Ihrer Unterklasse keine neuen Eigenschaften hinzufügen, können Sie zumindest die Oberklasse einfach bitten, das Ein- und Auspacken für Sie durchzuführen, daher der
super.init(coder: aDecoder)
Aufruf. Wenn Ihre Unterklasse komplexer ist, müssen Sie Ihren eigenen Serialisierungs- und Deserialisierungscode für die Unterklasse hinzufügen.Dies steht im Gegensatz zum Ansatz von Visual Studio, bei dem Code in eine versteckte Datei geschrieben wird, um das Objekt zur Laufzeit zu erstellen.
quelle
init(coder aCoder : NSCoder)
?awakeFromNib
funktioniert dies nicht.awakeFromNib
wird zur Laufzeit aufgerufen . Alles, was Sie in Interface Builder tun, ist während der Entwurfszeit . Das, was Sie in der Entwurfszeit getan haben, zur Laufzeit zu übertragen, istencodeWithCoder
(Speichern) undinit(coder:)
(Laden)awakeFromNib
oderinitWIthFrame
Die Anforderung, diesen Initialisierer zu implementieren, ist eine Folge von zwei Dingen:
Das Liskov-Substitutionsprinzip . Wenn S eine Unterklasse von T ist (z. B.
MyViewController
eine Unterklasse vonViewController
), müssen S-Objekte (Instanzen vonMyViewController
) dort eingesetzt werden können, wo T-Objekte (Instanzen vonViewController
) erwartet werden.Initialisierer werden in Swift nicht vererbt, wenn Initialisierer in der Unterklasse explizit definiert sind. Wenn ein Initialisierer explizit bereitgestellt wird, müssen alle anderen explizit bereitgestellt werden (der dann einfach aufgerufen werden kann
super.init(...)
). Siehe diese Frage zur Begründung. Es ist in Java, gilt aber immer noch.Nach Punkt 1 sollte
ViewController
dieMyViewController
Unterklasse alles können , was das Original kann . Eine solche Sache ist, von einer gegebenen initialisiert werden zu könnenNSCoder
. Ab Punkt 2MyViewController
erbt Ihre Unterklasse diese Fähigkeit nicht automatisch. Daher müssen Sie den Initialisierer, der diese Anforderung erfüllt, manuell angeben. In diesem Fall müssen Sie nur bis zur Oberklasse delegieren, damit diese das tut, was sie normalerweise tun würde.quelle