¿Por qué no puedo llamar al super.init () predeterminado en UIViewController en Swift?

84

No estoy usando un UIViewControllerde un guión gráfico y quiero tener una initfunción personalizada donde paso un NSManagedObjectIDde algún objeto. Solo quiero llamar super.init()como lo hice en Objective-C. Me gusta esto:

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

Pero obtengo el siguiente error del compilador:

Debe llamar al inicializador designado de la superclase UIViewController

¿Puedo simplemente dejar de hacer esto?

SirRupertIII
fuente

Respuestas:

119

El inicializador designado para UIViewControlleres initWithNibName:bundle:. Deberías llamar a eso en su lugar.

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

Si no tiene una plumilla, pase nilel nombre de la plumilla (el paquete también es opcional). Posteriormente, se podría construir una vista personalizada en loadViewo añadiendo a subvistas self.viewen viewDidLoad, al igual que solía hacerlo.

occulus
fuente
4
Entonces, ¿es actualmente imposible para mí crear un método de inicio personalizado en una subclase UIViewController que no sea de una plumilla?
SirRupertIII
1
Ahh, gracias !! Pasé "" por el nombre de la plumilla.
SirRupertIII
2
Oh, después de investigar un poco, resulta que initWithCoder:proviene del NSCodingprotocolo ... Todavía no puedo entender cuál es su papel en la inicialización de una instancia de UIViewController, si es un inicializador "designado" de UIViewController o cualquiera de sus superclases ... .
Nicolas Miari
6
¡Gracias! Para la copia rápida / pega simplemente llamar a esto después de ajustar sus letpropiedades, en su caso: super.init(nibName: nil, bundle: nil).
Ferran Maylinch
3
Init With coder se utiliza cuando es necesario restaurar el estado. Cuando guarda el estado del controlador de vista utilizando la función de restauración de estado, el codificador devolverá los valores que guardó cuando se guardó el estado. Desde allí, puede reconstruir el controlador de vista a su último estado inicial desde que cerró la aplicación. Entonces, para el usuario, es donde lo dejaron
Esko918
44

Otra buena solución es declarar su nuevo inicializador como convenienceinicializador de la siguiente manera:

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

    // ... store or user your objectId
}

Si declara que no hay inicializadores designados en su subclase, se heredan automáticamente y puede usarlos self.init()dentro de su inicializador de conveniencia.

En el caso de UIViewController, el método init predeterminado llamará init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)con nilambos argumentos (Command-Click en UIViewController le dará esa información).

TL; TR : Si prefiere trabajar programáticamente con UIViewControllers, aquí hay un ejemplo de trabajo completo que agrega un nuevo inicializador con un argumento personalizado:

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

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

        self.myString = myString
    }
}
Klaas
fuente
Esta es una solución más elegante y funciona en cualquier caso genérico
Ciprian
2
Intenté hacer esto en una extensión y recursivamente se llamó a sí mismo.
Danyal Aytekin
12
El "truco" de esta respuesta es que myStringestá configurado para ""que initno sea necesario. Esta solución se desmorona si no desea usar un valor inicial y, en ese caso, debe usarloself.init(nibName: nil, bundle:nil)
Dan Rosenstark
2
@Yar o hace que la myStringpropiedad sea opcional
Klaas
1
@Klaas sí: mi problema es que estaba usando los inicializadores SOLO para evitar opcionales y hacer que mi código se compile.
Dan Rosenstark
16

Para mejorar la respuesta del occulus :

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

Actualización: agregue el enlace

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

Según la documentación para iOS, el inicializador designado para UIViewController es initWithNibName: bundle:.

Si subclase UIViewController, debe llamar a la superimplementación de este método, incluso si no está utilizando un NIB.

Puedes hacerlo de la siguiente manera:

init(objectId : NSManagedObjectID) {

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

   // other code...
}

o

Declare un nuevo inicializador como inicializador de conveniencia:

 convenience init( objectId : NSManagedObjectID ) {

    self.init()

     // other code...

}

NcNc
fuente
1
Debes vincular al original para atribuirlo, en lugar de dejarlo como captura de pantalla.
Nathan Tuggy
Usé el mismo proceso que dijo @NcNc. Funcionó para mí. Aquí está el enlace
Anil Gupta
@NathanTuggy No, no debería. Los enlaces tienen una función para caducar o moverse algún día. ¿Quién quiere ver un error 404 en lugar de la información que está buscando?
mykolaj
1
@mykolaj: La información ya está aquí, en esta respuesta. (De lo contrario, habría estado marcando la eliminación como una respuesta de solo enlace). Pero la atribución también es importante para que cualquiera que lea esto pueda averiguar de dónde vino y acreditarlos. Una captura de pantalla no funciona para eso, pero un enlace sí. Si un enlace se pudre, eso es lamentable, pero no es posible que me digas que es una situación peor que nunca recibir ningún tipo de crédito. Las objeciones también lo ha hecho a respuestas-Link sólo están vinculando a sólo respuestas. No a enlaces. Enlace y también información es la formulación deseada.
Nathan Tuggy
@NathanTuggy Acabo de agregar el enlace. Gracias por recordarlo
NcNc