Schwerwiegender Fehler: Verwendung des nicht implementierten Initialisierers 'init (coder :)' für die Klasse

156

Ich beschloss, mein verbleibendes Projekt mit Swift fortzusetzen. Wenn ich UIViewcontrollermeinem Storyboard View Controller die benutzerdefinierte Klasse (Unterklasse von ) hinzufüge und das Projekt lade, stürzt die App plötzlich mit dem folgenden Fehler ab:

Schwerwiegender Fehler: Verwendung des nicht implementierten Initialisierers 'init (coder :)' für die Klasse

Dies ist ein Code:

import UIKit

class TestViewController: UIViewController {

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        // Custom initialization
    }

    override func viewDidLoad() {
        super.viewDidLoad()
              // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    /*
    // #pragma mark - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
}

Bitte schlagen Sie etwas vor

Pratik Bhiyani
quelle

Antworten:

207

Problem

Dies wird durch das Fehlen des Initialisierers init?(coder aDecoder: NSCoder)auf dem Ziel verursacht UIViewController. Diese Methode ist erforderlich, weil das Instanziieren von a UIViewControlleraus einem UIStoryboardAufruf erfolgt.

Um zu sehen, wie wir a UIViewControllervon a initialisieren UIStoryboard, schauen Sie bitte hier

Warum ist dies bei Objective-C kein Problem?

Weil Objective-C automatisch alle erforderlichen UIViewControllerInitialisierer erbt .

Warum erbt Swift die Initialisierer nicht automatisch?

Swift erbt die Initialisierer aus Sicherheitsgründen standardmäßig nicht. Es werden jedoch alle Initialisierer von der Oberklasse geerbt, wenn alle Eigenschaften einen Wert (oder optional) haben und die Unterklasse keine festgelegten Initialisierer definiert hat.


Lösung

1. Erste Methode

Manuelles Implementieren init?(coder aDecoder: NSCoder)auf dem ZielUIViewController

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

2. Zweite Methode

Wenn Sie init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)Ihr Ziel entfernen UIViewController, erben Sie alle erforderlichen Initialisierer aus der Oberklasse, wie Dave Wood auf seine Antwort unten hingewiesen hat


E-Riddie
quelle
4
Danke dafür. Schnelle Nachverfolgung ... Wenn Sie die TableViewController-Datei erstellen, enthält Xcode bereits. init(style: UITableViewStyle) { super.init(style: style) // Custom initialization } Warum können wir zwei Init-Funktionen haben? Und eine Idee, warum Apple die 2. Init standardmäßig nicht enthält?
Trevor McKendrick
Dies hat nichts mit iOS 7 oder iOS 8 zu tun. Dies hängt damit zusammen, wie Swift Intitializer erbt!
Sulthan
public init (Ansicht: UIViewController, Frame: CGRect) {self.viewController = Ansicht self.imageName = "" self.actionName = "" super.init (Frame: Frame)}
Scrainie
Die erste Methode hat funktioniert! Meine dynamische Tabelle ist endlich mit dynamischen Zellen gefüllt !!! Alles nur, weil die Leitung fatalError( "init(coder:) has not been implemented")meine App angehalten hat.
Jose Manuel Abarca Rodríguez
25

Eine andere Option neben @ 3r1d ist, stattdessen die folgende init-Methode aus Ihrer Klasse zu entfernen:

init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    // Custom initialization
}

Durch das Einschließen dieser init-Methode wird verhindert, dass die Unterklasse die init(coder aDecoder: NSCoder!)von ihrer Superklasse erbt . Wenn Sie es nicht einschließen, erbt Ihre Klasse beide.

Hinweis: Weitere Informationen finden Sie in der WWDC 2014-Sitzung 403 "Intermediate Swift" bei etwa 33:50.

Dave Wood
quelle
Vielen Dank, dass Sie auf die Erklärung in Sitzung 403 hingewiesen haben. Wenn die untergeordnete Klasse jedoch nur Convenience-Initialisierer hat, erbt sie die Super-Class-Initialisierer, oder?
Jamiltz
1
Ja. Sie verhindern nur, dass die Superklassen-Init-Methoden vererbt werden, wenn Sie Ihre eigenen Init-Methoden angeben (diejenigen, die Super-Inits aufrufen). Dann müssen Sie angeben, welche der Super-Inits unterstützt werden sollen, indem Sie sie Ihrer Klasse hinzufügen und einfach die Super-Version aufrufen (wie in der Antwort von @ 3r1d)
Dave Wood
Wenn Sie nur Convenience init () ohne (designiertes) init () in Ihrer untergeordneten Klasse haben, führt dies zu einem Kompilierungsfehler. Dies liegt daran, dass die Convenience-Funktion init () innerhalb der Funktionsdefinition self.init () aufrufen muss.
Ohmy
@narumolPug Das ist falsch. Sie müssen keine festgelegten initMethoden angeben. Ihre Kinderklasse wird sie von der Superklasse erben. Sie können immer noch anrufen, self.init()welche die Super-Version ausführen wird.
Dave Wood
Den genauen Moment des Videos finden Sie hier youtu.be/W1s9ZjDkSN0?t=2030
Honey
10

UICollectionViewCellsFügen Sie für Benutzer mit dem gleichen Problem mit swift den von @ 3r1d vorgeschlagenen Code zu Ihrer benutzerdefinierten UICollectionViewCellKlasse und nicht zum View Controller hinzu:

init(coder aDecoder: NSCoder!)
{
    super.init(coder: aDecoder)
}
Nick Yap
quelle
Auf welche UICollectionViewCell beziehen Sie sich? Init mit Codierer ist der Weg, um den viewController
E-Riddie
Nicht in diesem Beispiel, aber falls jemand ein Problem damit hat (ich habe es getan) ... Wenn Sie versuchen, einen UICollectionViewController zu verwenden, müssen Sie in Ihrer benutzerdefinierten .swift-Zellendatei init mit dem Codierer einfügen.
Nick Yap
2
Sie müssen diesen Code jedes Mal hinzufügen, wenn Sie diese Art der Instanziierung verwenden. Stackoverflow.com/questions/24035984/…
E-Riddie
3

Für diejenigen, die den Code in Swift benötigen:

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

[Bearbeiten] Dies war für eine ältere Version von Swift. Funktioniert möglicherweise nicht mehr.

MXV
quelle
3

Ich hatte dieses Problem in einer programmatischen collectionView-Zelle und obwohl die Operation nach einem VC fragt, bin ich bei der Suche nach einer Antwort immer noch auf diese Frage gestoßen. Für mich war das Problem, das ich hatte

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

implementiert, so dass die Top-Antwort nicht funktioniert hat. Was ich nicht in der Zelle hatte, war der Initialisierer:

// my programmatic cell was missing this
override init(frame: CGRect) {
    super.init(frame: frame)
}

Sobald ich es hinzugefügt habe, ist der Fehler verschwunden

Lance Samaria
quelle
1

Anstatt einige Methoden hinzuzufügen, damit der interne Mechanismus einwandfrei funktioniert, würde ich meine Attribute als @lazy definieren und sie direkt im Klassenbereich initialisieren.

hasancan85
quelle
Sie können Ihre Immobilie auch als optional über deklarieren ?.
Julian B.