Instanciar y presentar un viewController en Swift

300

Problema

Empecé a echar un vistazo de la nueva Swiften Xcode 6, y he intentado algunos proyectos de demostración y tutoriales. Ahora estoy atrapado en:

Crear instancias y luego presentar un viewControllerdesde un guión gráfico específico

Solución Objective-C

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"myStoryboardName" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"myVCID"];
[self presentViewController:vc animated:YES completion:nil];

¿Cómo lograr esto en Swift?

E-Riddie
fuente

Respuestas:

648

Esta respuesta fue revisada por última vez para Swift 5.2 y iOS 13.4 SDK.


Se trata de una nueva sintaxis y API ligeramente revisadas. La funcionalidad subyacente de UIKit no ha cambiado. Esto es cierto para la gran mayoría de los frameworks iOS SDK.

let storyboard = UIStoryboard(name: "myStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "myVCID")
self.present(vc, animated: true)

Si tiene problemas con init(coder:), consulte la respuesta de EridB .

akashivskyy
fuente
3
¡Incluso puedes omitir el ;! ;) ¿Te importaría elaborar sobre el as UIViewController? ¿Por qué es eso necesario?
Sebastian Wramba
55
asLa palabra clave se utiliza para la conversión de texto. Es lo mismo que (UIViewController *)anObjecten el objetivo c
Garoal
1
Sí, sé que puedo omitirlos, pero eso es parte del largo habito. : D Como instantiateViewControllerWithIdentifierdevuelve AnyObject( idequivalente en Swift) y declaro vccomo UIViewController, tengo que escribir AnyObjecten UIViewController.
akashivskyy
Hola amigos, me enfrento a un problema diferente, este código se ejecuta en el simulador, no en mi ipad2 que tiene iOS v7.1.2. Si no te importa, ayúdame a resolver este problema.
Indra
3
@akashivskyy Definitivamente, para ti. Pero tal vez no para algunos.
mmc
43

Para las personas que usan la respuesta de @ akashivskyy para crear instancias UIViewControllery tienen la excepción:

error fatal: uso del inicializador no implementado 'init (codificador :)' para la clase

Consejo rapido:

Implemente manualmente required init?(coder aDecoder: NSCoder)en su destino UIViewControllerque está tratando de instanciar

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

Si necesita más descripción, consulte mi respuesta aquí

E-Riddie
fuente
Si desea utilizar un iniciador personalizado, puede llamar al super con super.init (nibName: nil, bundle: nil) y el whew se cargará bien o lo llamará con el nombre del archivo NIB.
user1700737
44
@ user1700737 Estoy creando instancias de viewController haciendo referencia al guión gráfico, que ejecuta initWithCoder, no initWithNib. Consulte esta pregunta stackoverflow.com/questions/24036393/…
E-Riddie
Hola amigos, me enfrento a un problema diferente, este código se ejecuta en el simulador, no en mi ipad2 que tiene iOS v7.1.2. Si no te importa, ayúdame a resolver este problema.
Indra
@Indra, necesitas hacer otra pregunta sobre la pila, dame el enlace ¡Estaré encantado de ayudarte!
E-Riddie
En Swift 1.2 debe hacer init(coder aDecoder: NSCoder!)"requerido". Entonces ahora tienes que escribir lo siguiente:required init(coder aDecoder: NSCoder!)
Eduardo Viegas
18

Este enlace tiene las dos implementaciones:

Rápido:

let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
self.presentViewController(viewController, animated: false, completion: nil)

C objetivo

UIViewController *viewController = [[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:@"ViewController"];

Este enlace tiene un código para iniciar viewcontroller en el mismo guión gráfico

/*
 Helper to Switch the View based on StoryBoard
 @param StoryBoard ID  as String
*/
func switchToViewController(identifier: String) {
    let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(identifier) as! UIViewController
    self.navigationController?.setViewControllers([viewController], animated: false)

}
Abhijeet
fuente
15

¡La respuesta de akashivskyy funciona bien! Pero, en caso de que tenga problemas para regresar del controlador de vista presentado, esta alternativa puede ser útil. ¡Funcionó para mí!

Rápido:

let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController
// Alternative way to present the new view controller
self.navigationController?.showViewController(vc, sender: nil)

Obj-C:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MyStoryboardName" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"someViewController"];
[self.navigationController showViewController:vc sender:nil];
Nahuel Roldan
fuente
12

El código actualizado de Swift 4.2 es

let storyboard = UIStoryboard(name: "StoryboardNameHere", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.present(controller, animated: true, completion: nil)
Shahzaib Maqbool
fuente
7
// "Main" is name of .storybord file "
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
// "MiniGameView" is the ID given to the ViewController in the interfacebuilder
// MiniGameViewController is the CLASS name of the ViewController.swift file acosiated to the ViewController
var setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("MiniGameView") as MiniGameViewController
var rootViewController = self.window!.rootViewController
rootViewController?.presentViewController(setViewController, animated: false, completion: nil)

Esto funcionó bien para mí cuando lo puse en AppDelegate

Maxxafari
fuente
7

Si desea presentarlo modalmente, debería tener algo como abajo:

let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewControllerID")
self.showDetailViewController(vc as! YourViewControllerClassName, sender: self)
Hamid
fuente
5

Me gustaría sugerir una forma mucho más limpia. Esto será útil cuando tengamos varios guiones gráficos

1.Crea una estructura con todos tus guiones gráficos

struct Storyboard {
      static let main = "Main"
      static let login = "login"
      static let profile = "profile" 
      static let home = "home"
    }

2. Cree una extensión de UIStoryboard como esta

extension UIStoryboard {
  @nonobjc class var main: UIStoryboard {
    return UIStoryboard(name: Storyboard.main, bundle: nil)
  }
  @nonobjc class var journey: UIStoryboard {
    return UIStoryboard(name: Storyboard.login, bundle: nil)
  }
  @nonobjc class var quiz: UIStoryboard {
    return UIStoryboard(name: Storyboard.profile, bundle: nil)
  }
  @nonobjc class var home: UIStoryboard {
    return UIStoryboard(name: Storyboard.home, bundle: nil)
  }
}

Proporcione el identificador del guión gráfico como el nombre de la clase y use el siguiente código para crear instancias

let loginVc = UIStoryboard.login.instantiateViewController(withIdentifier: "\(LoginViewController.self)") as! LoginViewController
vijeesh
fuente
¿Para qué es @nonobjc?
StackRunner
1
@StackRunner esto no estará disponible para el objetivo c
XcodeNOOB
3

Swift 4:

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let yourVC: YourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as! YourVC
dibujó..
fuente
2

Si tiene un Viewcontroller que no usa ningún storyboard / Xib, puede presionar a este VC en particular como se muestra a continuación:

 let vcInstance : UIViewController   = yourViewController()
 self.present(vcInstance, animated: true, completion: nil)
Aks
fuente
Entiendo esto: "no se puede construir porque no tiene inicializadores accesibles".
Paul Bénéteau
los puntos de venta y otras relaciones hechas por el guión gráfico se pierden
jose920405
2

Swift 3 Storyboard

let settingStoryboard : UIStoryboard = UIStoryboard(name: "SettingViewController", bundle: nil)
let settingVC = settingStoryboard.instantiateViewController(withIdentifier: "SettingViewController") as! SettingViewController
self.present(settingVC, animated: true, completion: {

})
Giang
fuente
1

Sé que es un hilo viejo, pero creo que la solución actual (usando un identificador de cadena codificado para un controlador de vista dado) es muy propenso a errores.

He creado un script de tiempo de compilación (al que puede acceder aquí ), que creará una forma segura del compilador para acceder e instanciar los controladores de vista desde todos los guiones gráficos dentro del proyecto dado.

Por ejemplo, el controlador de vista llamado vc1 en Main.storyboard se instanciará de la siguiente manera:

let vc: UIViewController = R.storyboard.Main.vc1^  // where the '^' character initialize the controller
Nadav96
fuente
1

No importa lo que intenté, simplemente no funcionaría para mí, sin errores, pero tampoco un nuevo controlador de vista en mi pantalla. No sé por qué, pero envolverlo en la función de tiempo de espera finalmente lo hizo funcionar:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.0) {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller = storyboard.instantiateViewController(withIdentifier: "TabletViewController")
    self.present(controller, animated: true, completion: nil)
}
Starwave
fuente
1

Swift 5

let vc = self.storyboard!.instantiateViewController(withIdentifier: "CVIdentifier")
self.present(vc, animated: true, completion: nil)
Binoy jose
fuente