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.