2014-10-08 15 views
13

Dies ist früher zur Arbeit in Xcode 6.1 Beta außer Kraft zu setzen:Der richtige Weg, um einen Initialisierer in Swift 1.1

class MainViewController: NSViewController { 
    convenience override init() { 
    self.init(nibName: "MainView", bundle: nil) 
    } 
} 

Nachdem ich wechsle auf 6,1 GM2, es nicht kompilieren. Sieht so aus, als ob das Problem mit "failable initializers" in Swift 1.1 zusammenhängt. Ich habe versucht convenience override init?(), convenience init?() und override init?(), keiner funktioniert.

Also, was ist der richtige Weg, um diese Art von Initialisierungen ab heute zu überschreiben?

Antwort

20

Sie versuchen, init() - ein nicht-failable-Initialisierer - zu implementieren, indem Sie an init?(nibName:bundle:) delegieren, das ein nicht initialisierbarer Initialisierer ist. Dies funktioniert nicht: Wenn der Aufruf super.init fehlschlägt, bleibt eine nicht initialisierte Instanz übrig, die Swift nicht zulassen wird.

Oder, um es anders auszudrücken, das Ergebnis der Verwendung eines fehlbaren Initialisierers ist optional, und Sie können keinen optionalen anstelle eines nicht optionalen Werts verwenden. Und im Falle der Klasseninitialisierung und -vererbung können Sie eine nicht optionale self nicht durch eine optionale ersetzen - Sie können das Setup des Status self nur an einen anderen Initialisierer delegieren.

Stattdessen können Sie Optionalität/failability mit einem wenig Gesang und Tanz entfernen:

class MainViewController: NSViewController { 
    override init!(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 
     super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 
     // check state here and provide app-specific diagnostic if it's wrong 
    } 
    convenience override init() { 
     self.init(nibName: "MainView", bundle: nil) 
    } 

    // need this, too, or the compiler will complain that it's missing 
    required init?(coder: NSCoder) { 
     fatalError("not implemented") // ...or an actual implementation 
    } 
} 

Ein init! initializer erzeugt ein implizit ungeöffnet optional (IUV) - ebenso wie ein IUV-Typ verwendet werden kann zwischen Code zu überbrücken Dies funktioniert mit optionalen und nicht optionalen Werten, ein init! Initialisierer kann zwischen fehlbaren und nicht fehlbaren Initialisierern überbrücken. Sie können nicht von einem nicht failable-Initialisierer an einen nicht initialisierbaren Initialisierer delegieren, aber Sie können von einem nicht fehlbaren Initialisierer an einen Initialisierer init! und von einem init! Initialisierer an einen fehlinitialisierbaren Initialisierer delegieren.

Hier ist die NSViewController initializer Sie verwenden möchten, ist voll failable, so dass Sie es mit einem init! initializer außer Kraft setzen. Dann können Sie einen nicht ablehnbaren convenience init deklarieren, der an Ihren neuen Initialisierer init! delegiert.


Wir neigen oft dazu, IUOs, und durch Erweiterung init! initializers zu vermeiden, weil wir in der Regel zu wollen, entweder explizit erlauben (und erfordern Handhabung) Ausfall oder explizit zu verbieten. Einer der stärksten allgemeinen Anwendungsfälle für IUOs und deren Angehörige besteht jedoch darin, Bedingungen, die nur außerhalb Ihres Quellcodes garantiert sind, in Behauptungen umzuwandeln, die Ihr Code als unfehlbar behandeln kann. IBOutlet s sind ein großartiges Beispiel dafür - in deinem nib/storyboard garantierst du den Zustand deiner IBOutlet Variablen, aber der Compiler weiß nichts darüber - genau wie alles, was sonst noch mit Bundle-Ressourcen zu tun hat.

Dieser kleine Delegationstanz bringt die Last des Ausfalls an einen bestimmten, leicht debuggierbaren Ort in Ihrem Code - wenn der Anruf von init() bis super.init(nibName:bundle:) fehlschlägt, stürzt Ihre App ab. Aber Sie können erwarten, dass dieser Aufruf nur in sehr spezifischen (und meist zu Entwicklungszeiten) Bedingungen fehlschlägt.

+11

Wahnsinn. wie wäre es mit Kürze, bitte Apfel. –

+2

Dies gibt einen Fehler mit Swift 1.2: "Initialisierer überschreibt einen designierten Initialisierer nicht von seiner Oberklasse" ... d. H. Die Überschreibung von 2. init muss entfernt werden. Auch nach dem Kompilieren wirft der dritte Initialisierer seinen fatalen Fehler auf. Wie muss das umgesetzt werden? – BadmintonCat

+0

Es ist zu komplex. –

Verwandte Themen