2016-07-15 2 views
38

ich lerne und jedes Mal mache ich eine benutzerdefinierte Ansicht (benutzerdefinierte Tabellenansicht Zelle, Sammlung Sichtzelle, usw.) der Lehrer implementiert immer diese initializer:Was genau ist init Coder aDecoder? iOS Entwicklung von einem Online-Kurs

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

    } 

Warum genau muss ich immer muss das anrufen? Was tut es? Kann ich Eigenschaften in die init einfügen?

+2

Diese Antwort wird Ihnen helfen http://stackoverflow.com/questions/24036393/fatal-error-use-of-unimplemented-initializer-initcoder-for-class Vielen Dank –

+0

Wenn Sie ein Objekt ableiten, das 'NSCoding' implementiert dann müssen Sie diesen Initialisierer implementieren, da er für Klassen benötigt wird, die 'NSCoding' implementieren. Sie müssen mindestens die Superklassen-Init-Methode aufrufen. Wenn der "NSCoder" codierte Eigenschaften für Ihre Klasse enthält, können Sie diese Methode verwenden, um diese wiederherzustellen – Paulw11

+1

Versuchen Sie zu suchen. Diese Frage wurde hier oft beantwortet. – matt

Antwort

7

Die Forderung, dass initializer zu implementieren ist eine Folge von zwei Dinge:

  1. Die Liskov substitution principle. Wenn S eine Unterklasse von T ist (z. B. MyViewController ist eine Unterklasse von ViewController), müssen S-Objekte (Instanzen von MyViewController) ersetzt werden können, wobei T-Objekte (Instanzen von ViewController) erwartet werden.

  2. Initialisierer werden in Swift nicht vererbt, wenn Initialisierer explizit in der Unterklasse definiert sind. Wenn ein Initialisierer explizit bereitgestellt wird, müssen alle anderen explizit angegeben werden (die dann einfach super.init(...) aufrufen kann). Siehe this question für Begründung. Es ist in Java, aber es gilt immer noch.

von Punkt 1, alles, was das Original ViewController tun können, die MyViewController Unterklasse sollte tun können. Eine solche Sache ist es, von einem gegebenen NSCoder initialisiert werden zu können. Nach Punkt 2 erbt Ihre Unterklasse MyViewController diese Fähigkeit nicht automatisch. Daher müssen Sie den Initialisierer manuell bereitstellen, der diese Anforderung erfüllt. In diesem Fall müssen Sie nur an die Oberklasse delegieren, damit sie das tut, was sie normalerweise tun würde.

+0

Es macht durchaus Sinn, dass Konstruktoren nicht vererbt werden: Wenn Sie eine Instanz der abgeleiteten Klasse mit dem (geerbten) Initialisierer der Basisklasse initialisieren, werden die nicht vererbten Eigenschaften, die von der abgeleiteten Klasse neu definiert ("hinzugefügt" wurden) niemals initialisiert werden. –

+0

Eigentlich werden Initialisierer in Swift vererbt, vorausgesetzt, Sie stellen in Ihrer Unterklasse keine eigenen Initialisierungsimplementierungen bereit. Wenn Ihre neu definierten nicht geerbten Eigenschaften Standardwerte haben, können Sie keine Initialisierer in Ihre Unterklasse schreiben und einfach alle Initialisierer Ihrer Oberklasse erben. Siehe [hier] (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID222) – TheBaj

+0

@TheBaj Guter Punkt Das habe ich übersehen. – Alexander

45

Ich werde diese Antwort aus der entgegengesetzten Richtung starten: Was, wenn Sie den Zustand Ihrer Ansicht auf der Festplatte speichern möchten? Dies ist bekannt als Serialisierung. Die Umkehrung ist Deserialisierung - Wiederherstellung des Zustands des Objekts von der Festplatte.

Das NSCoding Protokoll definiert zwei Methoden zur Serialisierung und Deserialisierung Objekte:

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

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

Warum ist es in der benutzerdefinierten Klasse benötigt? Die Antwort ist Interface Builder. Wenn Sie ein Objekt auf ein Storyboard ziehen und es konfigurieren, serialisiert Interface Builder den Status dieses Objekts auf der Festplatte und deserialisiert es anschließend, wenn das Storyboard auf dem Bildschirm angezeigt wird. Sie müssen Interface Builder mitteilen, wie Sie diese ausführen. Wenn Sie Ihrer Unterklasse keine neuen Eigenschaften hinzufügen, können Sie einfach die Oberklasse bitten, das Packen und Entpacken für Sie durchzuführen, daher der Aufruf super.init(coder: aDecoder). Wenn Ihre Unterklasse komplexer ist, müssen Sie einen eigenen Serialisierungs- und Deserialisierungscode für die Unterklasse hinzufügen.

Dies steht im Gegensatz zu der Visual Studio-Ansatz, Code in eine versteckte Datei zu schreiben, um das Objekt zur Laufzeit zu machen.

+0

Warum nicht alles in watchFromNib setzen und vergessen '' init (coder aCoder: NSCoder) ''? – Honey

+0

@Honey - mit einem Wort, "manchmal können Sie das nicht tun". Das kann man normalerweise, aber nicht immer. – Fattie

+0

@Fattie sind die Details nicht zu komplex oder unnötig zu wissen? Wenn nicht, stört es Sie zu erklären? – Honey