Instanciar e apresentar uma viewController no Swift

300

Questão

Comecei a tomar um olhar de novo Swiftsobre Xcode 6, e eu tentei alguns projectos de demonstração e tutoriais. Agora estou preso em:

Instanciando e depois apresentando um viewControllerde um storyboard específico

Solução Objective-C

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

Como conseguir isso no Swift?

E-Riddie
fonte

Respostas:

648

Esta resposta foi revisada pela última vez no Swift 5.2 e iOS 13.4 SDK.


É tudo uma questão de nova sintaxe e APIs ligeiramente revisadas. A funcionalidade subjacente do UIKit não mudou. Isso é verdade para a grande maioria das estruturas do SDK do iOS.

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

Se você estiver tendo problemas init(coder:), consulte a resposta do EridB .

akashivskyy
fonte
3
Você pode até omitir o ;! ;) Você se importaria de elaborar o as UIViewController? Por que isso é necessário?
Sebastian Wramba
5
asA palavra-chave é usada para tipografia. É o mesmo que (UIViewController *)anObjectno objetivo c
Garoal 4/14
1
Sim, eu sei que posso omiti-los, mas isso faz parte do longo hábito. : D Como instantiateViewControllerWithIdentifierretornos AnyObject( idequivalente em Swift) e declaro vccomo UIViewController, tenho que escrever AnyObjectpara UIViewController.
precisa saber é o seguinte
Olá amigos, estou enfrentando algum problema diferente, este código é executado no simulador, não no meu ipad2 que possui o iOS v7.1.2. Se você não se importa, ajude-me a resolver esse problema.
Indra
3
@akashivskyy Definitivamente, para você. Mas talvez não para alguns.
mmc
43

Para as pessoas que usam a resposta de @ akashivskyy para instanciar UIViewControllere estão tendo a exceção:

erro fatal: uso do inicializador não implementado 'init (coder :)' para a classe

Dica rápida:

Implementar manualmente required init?(coder aDecoder: NSCoder)em seu destino UIViewControllerque você está tentando instanciar

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

Se você precisar de mais descrição, consulte a minha resposta aqui

E-Riddie
fonte
Se você deseja usar o iniciador personalizado, basta chamar o super com super.init (nibName: nil, bundle: nil) e o whew será carregado com facilidade ou será chamado com o nome do arquivo NIB.
precisa saber é o seguinte
4
@ user1700737 Estou instanciando o viewController referente ao storyboard, que executa initWithCoder, não initWithNib. Consulte esta questão stackoverflow.com/questions/24036393/…
E-Riddie 10/14/14 /
Olá amigos, estou enfrentando algum problema diferente, este código é executado no simulador, não no meu ipad2 que possui o iOS v7.1.2. Se você não se importa, ajude-me a resolver esse problema.
Indra
@ Indra você precisa fazer outra pergunta na pilha, me dê o link Ficarei feliz em ajudá-lo!
E-Riddie
No Swift 1.2, você deve tornar init(coder aDecoder: NSCoder!)"obrigatório". Então agora você deve escrever o seguinte:required init(coder aDecoder: NSCoder!)
Eduardo Viegas
18

Este link possui as duas implementações:

Rápido:

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

Objetivo C

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

Este link possui um código para iniciar o viewcontroller no mesmo 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)

}
Abhijeet
fonte
15

A resposta de akashivskyy funciona muito bem! Porém, caso você tenha algum problema ao retornar do controlador de exibição apresentado, essa alternativa pode ser útil. Funcionou para mim!

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
fonte
12

O código atualizado do Swift 4.2 é

let storyboard = UIStoryboard(name: "StoryboardNameHere", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.present(controller, animated: true, completion: nil)
Shahzaib Maqbool
fonte
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)

Isso funcionou bem para mim quando o coloquei no AppDelegate

Maxxafari
fonte
7

Se você deseja apresentá-lo de forma modal, deve ter algo como:

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

Eu gostaria de sugerir uma maneira muito mais limpa. Isso será útil quando tivermos vários storyboards

1.Crie uma estrutura com todos os seus storyboards

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

2. Crie uma extensão 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)
  }
}

Dê ao identificador do storyboard o nome da classe e use o código abaixo para instanciar

let loginVc = UIStoryboard.login.instantiateViewController(withIdentifier: "\(LoginViewController.self)") as! LoginViewController
vijeesh
fonte
O que é @nonobjc?
StackRunner
1
@StackRunner isso não estará disponível para o objetivo c
XcodeNOOB
3

Swift 4:

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

Se você tem um Viewcontroller que não usa nenhum storyboard / Xib, pode enviar para esse VC em particular, como na chamada abaixo:

 let vcInstance : UIViewController   = yourViewController()
 self.present(vcInstance, animated: true, completion: nil)
Aks
fonte
Eu entendi o seguinte: "não pode ser construído porque não possui inicializadores acessíveis".
Paul Bénéteau
as saídas e outras relações feitas pelo storyboard são perdidos
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
fonte
1

Eu sei que é um thread antigo, mas acho que a solução atual (usando o identificador de string codificado para determinado controlador de exibição) é muito propensa a erros.

Eu criei um script de tempo de compilação (que você pode acessar aqui ), que criará uma maneira segura do compilador para acessar e instanciar controladores de exibição de todo o storyboard no projeto em questão.

Por exemplo, o controlador de exibição chamado vc1 no Main.storyboard será instanciado da seguinte forma:

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

Não importa o que eu tentei, ele simplesmente não funcionaria para mim - sem erros, mas também sem um novo controlador de exibição na tela. Não sei por que, mas envolvê-lo na função timeout finalmente o fez 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
fonte
1

Swift 5

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