Perché non riesco a chiamare il super.init () predefinito su UIViewController in Swift?


85

Non sto usando uno UIViewControllerda uno storyboard e voglio avere una initfunzione personalizzata in cui passo un NSManagedObjectIDoggetto. Voglio solo chiamare super.init()come ho fatto in Objective-C. Come questo:

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

Ma ottengo il seguente errore del compilatore:

È necessario chiamare l'inizializzatore designato della superclasse UIViewController

Posso semplicemente non farlo più?

Risposte:


121

L'inizializzatore designato per UIViewControlleris initWithNibName:bundle:. Dovresti chiamarlo invece.

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

Se non hai un pennino, passa nilper il nibName (anche il bundle è opzionale). Quindi potresti costruire una visualizzazione personalizzata in loadViewo aggiungendo sottoviste a self.viewin viewDidLoad, come facevi prima .


4
Quindi è attualmente impossibile per me creare un metodo di inizializzazione personalizzato in una sottoclasse UIViewController che non proviene da un pennino?
SirRupertIII

1
Ahh, grazie !! Passavo "" per il nome del pennino.
SirRupertIII

2
Oh, dopo un po 'di ricerca, si scopre che initWithCoder:proviene dal NSCodingprotocollo ... Non riesco ancora a capire qual è il suo ruolo nell'inizializzazione di un'istanza di UIViewController, se è un inizializzatore "designato" di UIViewController o una delle sue superclassi .. .
Nicolas Miari

6
Grazie! Per copia veloce / incolla basta chiamare questo dopo aver impostato le vostre letproprietà, se del caso: super.init(nibName: nil, bundle: nil).
Ferran Maylinch

3
Init With coder viene utilizzato quando è necessario eseguire il ripristino dello stato. Quando si salva lo stato del viewcontroller utilizzando la funzionalità di ripristino dello stato, il programmatore restituirà i valori salvati al momento del salvataggio dello stato. Da lì puoi ricostruire il controller della visualizzazione fino al suo ultimo stato iniziale da quando hai chiuso l'applicazione. Quindi per l'utente è da dove si era interrotto
Esko918

44

Un'altra bella soluzione è dichiarare il tuo nuovo inizializzatore come convenienceinizializzatore come segue:

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

    // ... store or user your objectId
}

Se non dichiari alcun inizializzatore designato nella tua sottoclasse, vengono ereditati automaticamente e puoi utilizzarli self.init()all'interno del tuo inizializzatore di convenienza.

In caso di UIViewController, il metodo di inizializzazione predefinito chiamerà init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)con nilper entrambi gli argomenti (Comando-clic su UIViewController ti darà queste informazioni).

TL; TR : Se preferisci lavorare a livello di UIViewControllercodice con s, ecco un esempio funzionante completo che aggiunge un nuovo inizializzatore con un argomento personalizzato:

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

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

        self.myString = myString
    }
}

Questa è una soluzione più elegante e funziona in ogni caso generico
Ciprian

2
Ho provato a farlo in un'estensione e si chiamava ricorsivamente.
Danyal Aytekin

12
Il "trucco" di questa risposta è che myStringè impostato su ""quindi initnon è richiesto. Questa soluzione va in pezzi se non si desidera utilizzare un valore iniziale, e in tal caso è necessario utilizzareself.init(nibName: nil, bundle:nil)
Dan Rosenstark

2
@Yar o rendi la myStringproprietà un optional
Klaas

1
@Klaas sì: il mio problema è che stavo usando SOLO gli inizializzatori per evitare gli optional e far compilare il mio codice.
Dan Rosenstark

19

Per migliorare la risposta dell'occulus :

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

16

Aggiorna: aggiungi il link

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

Secondo la documentazione per iOS, l'inizializzatore designato per UIViewController è initWithNibName: bundle:.

Se si sottoclasse UIViewController, è necessario chiamare la super implementazione di questo metodo, anche se non si utilizza un NIB.

Puoi farlo come segue:

init(objectId : NSManagedObjectID) {

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

   // other code...
}

o

Dichiarare un nuovo inizializzatore come inizializzatore di convenienza:

 convenience init( objectId : NSManagedObjectID ) {

    self.init()

     // other code...

}


1
Dovresti collegarti all'originale per l'attribuzione, piuttosto che lasciarlo come screencap.
Nathan Tuggy

Ho usato lo stesso processo di @NcNc ha detto. Ha funzionato per me. Ecco il link
Anil Gupta

@NathanTuggy No, non dovrebbe. I collegamenti hanno una funzione per scadere o spostarsi un giorno. Chi vuole vedere un errore 404 invece delle informazioni che sta cercando?
mykolaj

1
@mykolaj: Le informazioni sono già qui, in questa risposta. (Altrimenti avrei contrassegnato l'eliminazione come risposta solo per il collegamento.) Ma anche l'attribuzione è importante in modo che chiunque legga questo possa scoprire da dove proviene e attribuire loro un merito. Uno screenshot non funziona per questo, ma un collegamento sì. Se un collegamento marcisce, beh, è ​​un peccato, ma non puoi dirmi che è una situazione peggiore che non ricevere alcun tipo di credito. Le obiezioni ha così alle risposte link-solo sono a Link- solo risposte. Non ai link. Link e anche informazioni sono la formulazione desiderata.
Nathan Tuggy

@NathanTuggy Ho appena aggiunto il collegamento. Grazie per il tuo
promemoria
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.