Mit dem folgenden Code versuche ich, eine einfache Modellklasse und ihren fehlgeschlagenen Initialisierer zu definieren, der ein (json-) Wörterbuch als Parameter verwendet. Der Initialisierer sollte zurückgeben, nil
wenn der Benutzername im ursprünglichen JSON nicht definiert ist.
1. Warum wird der Code nicht kompiliert? Die Fehlermeldung lautet:
Alle gespeicherten Eigenschaften einer Klasseninstanz müssen initialisiert werden, bevor nil von einem Initialisierer zurückgegeben wird.
Das macht keinen Sinn. Warum sollte ich diese Eigenschaften initialisieren, wenn ich zurückkehren möchte nil
?
2. Ist mein Ansatz der richtige oder gibt es andere Ideen oder gemeinsame Muster, um mein Ziel zu erreichen?
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
if let value: String = dictionary["user_name"] as? String {
userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
}
}
swift
object-initializers
Kai Huppmann
quelle
quelle
canSetCalculableProperties
booleschen Parameter hinzugefügt , mit dem mein Initialisierer Eigenschaften berechnen kann, die im laufenden Betrieb erstellt werden können oder nicht. Wenn beispielsweise eindateCreated
Schlüssel fehlt und ich die EigenschaftcanSetCalculableProperties
im laufenden Betrieb festlegen kann, weil der Parameter true ist, setze ich ihn einfach auf das aktuelle Datum.Antworten:
Update: Aus dem Swift 2.2-Änderungsprotokoll (veröffentlicht am 21. März 2016):
Für Swift 2.1 und früher:
Gemäß der Dokumentation von Apple (und Ihrem Compilerfehler) muss eine Klasse alle gespeicherten Eigenschaften initialisieren, bevor sie
nil
von einem fehlgeschlagenen Initialisierer zurückkehrt:Hinweis: Es funktioniert tatsächlich gut für Strukturen und Aufzählungen, nur nicht für Klassen.
Die vorgeschlagene Methode zum Behandeln gespeicherter Eigenschaften, die nicht initialisiert werden können, bevor der Initialisierer fehlschlägt, besteht darin, sie als implizit entpackte Optionen zu deklarieren.
Beispiel aus den Dokumenten:
In Ihrem Fall wird der Kompilierungsfehler jedoch nicht durch einfaches Definieren
userName
alsString!
behoben, da Sie sich weiterhin um die Initialisierung der Eigenschaften Ihrer Basisklasse kümmern müssenNSObject
. Glücklicherweise können Sie mituserName
definiert als aString!
tatsächlichsuper.init()
vor Ihnen aufrufen ,return nil
wodurch IhreNSObject
Basisklasse initiiert und der Kompilierungsfehler behoben wird.quelle
Product
Klasse) kann keinen Initialisierungsfehler auslösen, bevor ein bestimmter Wert zugewiesen wird, obwohl die Dokumente dies für möglich halten. Die Dokumente sind nicht mit der neuesten Swift-Version synchronisiert. Es wird empfohlen, esvar
stattdessen vorerst zu machenlet
. Quelle: Chris Lattner .Laut Chris Lattner ist dies ein Fehler. Folgendes sagt er:
Quelle
BEARBEITEN:
Swift ist jetzt Open Source und gemäß diesem Änderungsprotokoll ist es jetzt in Snapshots von Swift 2.2 behoben
quelle
Ich akzeptiere, dass die Antwort von Mike S die Empfehlung von Apple ist, aber ich denke nicht, dass dies die beste Vorgehensweise ist. Der Sinn eines starken Typsystems besteht darin, Laufzeitfehler in die Kompilierungszeit zu verschieben. Diese "Lösung" macht diesen Zweck zunichte. IMHO wäre es besser, den Benutzernamen zu initialisieren
""
und ihn dann nach der super.init () zu überprüfen. Wenn leere Benutzernamen zulässig sind, setzen Sie ein Flag.quelle
Eine andere Möglichkeit, die Einschränkung zu umgehen, besteht darin, mit einer Klassenfunktion zu arbeiten, um die Initialisierung durchzuführen. Vielleicht möchten Sie diese Funktion sogar in eine Erweiterung verschieben:
Die Verwendung würde werden:
quelle
Obwohl Swift 2.2 veröffentlicht wurde und Sie das Objekt nicht mehr vollständig initialisieren müssen, bevor der Initialisierer fehlschlägt, müssen Sie Ihre Pferde halten, bis https://bugs.swift.org/browse/SR-704 behoben ist.
quelle
Ich fand heraus , dies kann in Swift 1.2 erfolgen
Es gibt einige Bedingungen:
Beispiel:
quelle
Auszug aus: Apple Inc. „ Die schnelle Programmiersprache. IBooks. https://itun.es/sg/jEUH0.l
quelle
Sie können Convenience Init verwenden :
quelle