Crea un'istanza e presenta un viewController in Swift


300

Problema

Ho iniziato a prendere uno sguardo di nuovo Swiftsu Xcode 6, e ho provato alcuni progetti dimostrativi e tutorial. Ora sono bloccato a:

Creare un'istanza e quindi presentare un viewControllerda uno storyboard specifico

Soluzione Objective-C

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

Come ottenere questo risultato su Swift?

Risposte:


648

Questa risposta è stata rivista l'ultima volta per Swift 5.2 e iOS 13.4 SDK.


È tutta una questione di nuova sintassi e API leggermente riviste. Le funzionalità di base di UIKit non sono cambiate. Questo è vero per la stragrande maggioranza dei framework SDK per iOS.

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

In caso di problemi init(coder:), consultare la risposta di EridB .


3
Puoi persino omettere il ;! ;) Ti dispiacerebbe approfondire il as UIViewController? Perché è necessario?
— Sebastian Wramba,

5
asla parola chiave viene utilizzata per la tipografia. È lo stesso (UIViewController *)anObjectdell'obiettivo c
— Garoal

1
Sì, lo so che posso ometterli, ma fa parte del lungo habbit. : D Come instantiateViewControllerWithIdentifierritorni AnyObject( idequivalente in Swift) e dichiaro vccome UIViewController, devo digitare AnyObjecta UIViewController.
— Akashivskyy,

Ciao amici, sto affrontando un problema diverso, questo codice funziona sul simulatore non sul mio ipad2 con iOS v7.1.2. Se non ti dispiace aiutami a risolvere questo problema.
— Indra,

3
@akashivskyy Sicuramente, a te. Ma forse non per alcuni.
— mmc,

43

Per le persone che usano la risposta di @ akashivskyy per creare un'istanza UIViewControllere avere l'eccezione:

errore fatale: uso dell'inizializzatore non implementato 'init (coder :)' per la classe

Suggerimento veloce:

Implementare manualmente required init?(coder aDecoder: NSCoder)a destinazione UIViewControllerche si sta tentando di creare un'istanza

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

Se hai bisogno di maggiori descrizioni, fai riferimento alla mia risposta qui


Se vuoi usare l'iniziatore personalizzato puoi semplicemente chiamare il super con super.init (nibName: nil, bundle: nil) e whew caricherà bene o lo chiamerà con il nome del loro file NIB.
— user1700737

4
@ user1700737 Sto istanziando viewController facendo riferimento allo storyboard, che esegue initWithCoder, non initWithNib. Fare riferimento a questa domanda stackoverflow.com/questions/24036393/...
— E-Riddie

Ciao amici, sto affrontando un problema diverso, questo codice funziona sul simulatore non sul mio ipad2 con iOS v7.1.2. Se non ti dispiace aiutami a risolvere questo problema.
— Indra,

@Indra devi fare un'altra domanda in pila, dammi il link Ill sarò felice di aiutarti!
— E-Riddie,

Su Swift 1.2 devi fare init(coder aDecoder: NSCoder!)"richiesto". Quindi ora devi scrivere quanto segue:required init(coder aDecoder: NSCoder!)
— Eduardo Viegas,

18

Questo collegamento ha entrambe le implementazioni:

Swift:

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

Obiettivo C

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

Questo collegamento ha un codice per avviare viewcontroller nello stesso storyboard

/*
 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)

}

15

La risposta di Akashivsky funziona perfettamente! Tuttavia, in caso di problemi con il ritorno dal controller della vista presentato, questa alternativa può essere utile. Ha funzionato per me!

Swift:

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];

12

Il codice aggiornato di Swift 4.2 è

let storyboard = UIStoryboard(name: "StoryboardNameHere", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.present(controller, animated: true, completion: nil)

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)

Questo ha funzionato bene per me quando l'ho messo in AppDelegate


7

Se vuoi presentarlo modalmente, dovresti avere qualcosa come muggito:

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

5

Vorrei suggerire un modo molto più pulito. Questo sarà utile quando avremo più storyboard

1.Crea una struttura con tutti i tuoi storyboard

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

2. Creare un'estensione UIStoryboard come questa

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)
  }
}

Assegna all'identificatore dello storyboard il nome della classe e usa il codice seguente per creare un'istanza

let loginVc = UIStoryboard.login.instantiateViewController(withIdentifier: "\(LoginViewController.self)") as! LoginViewController

A cosa serve @nonobjc?
— StackRunner

1
@StackRunner questo non sarà disponibile per l'obiettivo c
— XcodeNOOB,

3

Swift 4:

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

2

Se hai un Viewcontroller che non utilizza uno storyboard / Xib, puoi spingere verso questo particolare VC come sotto chiamata:

 let vcInstance : UIViewController   = yourViewController()
 self.present(vcInstance, animated: true, completion: nil)

Ottengo questo: "non può essere costruito perché non ha inizializzatori accessibili".
— Paul Bénéteau,

i punti vendita e le altre relazioni fatte dallo storyboard sono persi
— 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: {

})

1

So che è un vecchio thread, ma penso che la soluzione attuale (usando l'identificatore di stringa codificato per un determinato controller di visualizzazione) sia molto soggetta a errori.

Ho creato uno script di build time (a cui puoi accedere qui ), che creerà un modo sicuro per il compilatore per accedere e creare un'istanza dei controller di visualizzazione da tutti gli storyboard all'interno del progetto dato.

Ad esempio, il controller di visualizzazione chiamato vc1 in Main.storyboard verrà istanziato in questo modo:

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

1

Non importa quello che ho provato, semplicemente non avrebbe funzionato per me - nessun errore, ma nemmeno un nuovo controller di visualizzazione sul mio schermo. Non so perché, ma avvolgendolo nella funzione di timeout alla fine lo ha fatto funzionare:

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)
}

1

Swift 5

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

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.