Warum kann ich die Standardeinstellung super.init () auf UIViewController in Swift nicht aufrufen?

81

Ich verwende kein UIViewControllerStoryboard und möchte eine benutzerdefinierte initFunktion haben, bei der ich ein NSManagedObjectIDObjekt übergebe. Ich möchte nur anrufen, super.init()wie ich es in Objective-C getan habe. So was:

init(objectId: NSManagedObjectID) {
    super.init()
}

Aber ich bekomme folgenden Compilerfehler:

Muss den designierten Initialisierer des UIViewControllers der Oberklasse aufrufen

Kann ich das einfach nicht mehr machen?

Sir RupertIII
quelle

Antworten:

118

Der vorgesehene Initialisierer für UIViewControllerist initWithNibName:bundle:. Sie sollten das stattdessen anrufen.

Siehe http://www.bignerdranch.com/blog/real-iphone-crap-2-initwithnibnamebundle-is-the-designated-initializer-of-uiviewcontroller/

Wenn Sie keine Schreibfeder haben, geben Sie nilden Schreibfedernamen ein (das Bundle ist ebenfalls optional). Anschließend können Sie eine benutzerdefinierte Ansicht in loadViewoder durch Hinzufügen von Unteransichten zu self.viewin erstellen viewDidLoad, wie Sie es früher getan haben .

Occulus
quelle
4
Daher ist es mir derzeit unmöglich, eine benutzerdefinierte Init-Methode in einer UIViewController-Unterklasse zu erstellen, die nicht von einer Schreibfeder stammt.
SirRupertIII
1
Ahh, danke !! Ich habe "" für den Spitznamen eingegeben.
Sir RupertIII
2
Oh, nach ein wenig Graben stellt sich heraus, dass es initWithCoder:aus dem NSCodingProtokoll stammt ... Ich kann immer noch nicht herausfinden, welche Rolle es bei der Initialisierung einer UIViewController-Instanz spielt, ob es sich um einen "designierten" Initialisierer von UIViewController oder einer seiner Superklassen handelt. .
Nicolas Miari
6
Vielen Dank! Rufen Sie dies zum schnellen Kopieren / Einfügen auf, nachdem Sie Ihre letEigenschaften festgelegt haben, falls vorhanden : super.init(nibName: nil, bundle: nil).
Ferran Maylinch
3
Init With coder wird verwendet, wenn Sie eine Zustandswiederherstellung durchführen müssen. Wenn Sie den Status des Viewcontrollers mithilfe der Statuswiederherstellungsfunktion speichern, gibt der Codierer die Werte zurück, die Sie beim Speichern des Status gespeichert haben. Von dort aus können Sie den View Controller ab dem Zeitpunkt, zu dem Sie die Anwendung geschlossen haben, auf den letzten Ausgangszustand zurücksetzen. Also für den Benutzer ist es, wo sie
aufgehört haben
42

Eine andere gute Lösung besteht darin, Ihren neuen convenienceInitialisierer wie folgt als Initialisierer zu deklarieren :

convenience init( objectId : NSManagedObjectID ) {
    self.init()

    // ... store or user your objectId
}

Wenn Sie in Ihrer Unterklasse überhaupt keine festgelegten Initialisierer deklarieren, werden diese automatisch vererbt und Sie können sie self.init()in Ihrem praktischen Initialisierer verwenden.

Im Falle von UIViewController wird die Standard - Init - Methode aufrufen , init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)mit nilfür beide Argumente (Befehlstaste auf UIViewController geben Ihnen diese Informationen).

TL; TR : Wenn Sie lieber programmgesteuert mit UIViewControllers arbeiten möchten, finden Sie hier ein vollständiges Arbeitsbeispiel, das einen neuen Initialisierer mit einem benutzerdefinierten Argument hinzufügt:

class MyCustomViewController: UIViewController {
    var myString: String = ""

    convenience init( myString: String ) {
        self.init()

        self.myString = myString
    }
}
Klaas
quelle
Dies ist eine elegantere Lösung und funktioniert in jedem generischen Fall
Ciprian
2
Ich habe versucht, dies in einer Erweiterung zu tun, und es hat sich rekursiv selbst genannt.
Danyal Aytekin
11
Der "Trick" zu dieser Antwort ist, dass myStringso eingestellt ist, ""dass das initnicht erforderlich ist. Diese Lösung fällt auseinander, wenn Sie keinen Anfangswert verwenden möchten, und in diesem Fall müssen Sie verwendenself.init(nibName: nil, bundle:nil)
Dan Rosenstark
2
@Yar oder Sie machen die myStringEigenschaft optional
Klaas
1
@Klaas ja: Mein Problem ist, dass ich NUR die Initialisierer verwendet habe, um Optionen zu vermeiden und meinen Code zum Kompilieren zu bringen.
Dan Rosenstark
15

Um die Antwort des Okkulus zu verbessern :

init() {
     super.init(nibName: nil, bundle: nil)
}
Vyacheslav
quelle
14

Update: Fügen Sie den Link hinzu

https://developer.apple.com/documentation/uikit/uiviewcontroller/1621359-init

Gemäß der Dokumentation für iOS ist der designierte Initialisierer für UIViewController initWithNibName: bundle:.

Wenn Sie UIViewController unterordnen, müssen Sie die Super-Implementierung dieser Methode aufrufen, auch wenn Sie keine NIB verwenden.

Sie können dies wie folgt tun:

init(objectId : NSManagedObjectID) {

    super.init(nibName: (xib's name or nil'), bundle: nil)

   // other code...
}

oder

Deklarieren Sie einen neuen Initialisierer als praktischen Initialisierer:

 convenience init( objectId : NSManagedObjectID ) {

    self.init()

     // other code...

}}

NcNc
quelle
1
Sie sollten zur Zuordnung auf das Original verlinken, anstatt es als Bildschirmabdeckung zu belassen.
Nathan Tuggy
Ich habe den gleichen Prozess wie @NcNc verwendet. Es hat bei mir funktioniert. Hier ist Link
Anil Gupta
@ NathanTuggy Nein, sollte er nicht. Links haben eine Funktion, die eines Tages abläuft oder verschoben werden kann. Wer möchte einen 404-Fehler anstelle einer gesuchten Information sehen?
Mykolaj
1
@mykolaj: Die Informationen sind bereits hier, in dieser Antwort. (Andernfalls hätte ich das Löschen als reine Linkantwort markiert.) Die Zuordnung ist jedoch auch wichtig, damit jeder, der dies liest, herausfinden kann, woher es stammt, und es gutschreiben kann. Ein Screenshot funktioniert dafür nicht, ein Link jedoch. Wenn ein Link verrottet, ist das unglücklich, aber Sie können mir unmöglich sagen, dass dies eine schlimmere Situation ist, als überhaupt keine Gutschrift zu erhalten. Die Einwände SO muss Link nur Antworten auf Link- nur Antworten. Keine Links. Link und auch Info ist die gewünschte Formulierung.
Nathan Tuggy
@ NathanTuggy Ich habe gerade den Link hinzugefügt. Vielen Dank für Ihre Erinnerung
NcNc