Utwórz i przedstaw widok kontrolera w Swift

299

Kwestia

Zacząłem przyjrzeniu nowej Swiftpozycji ON Xcode 6, a próbowałem kilka projektów demonstracyjnych i samouczków. Teraz utknąłem w:

Tworzenie wystąpienia, a następnie prezentacja viewControllerz określonej scenorysu

Rozwiązanie Objective-C

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

Jak to osiągnąć w Swift?

E-Riddie
źródło

Odpowiedzi:

647

Ta odpowiedź została ostatnio poprawiona dla zestawu SDK Swift 5.2 i iOS 13.4.


Wszystko zależy od nowej składni i nieco zmienionych interfejsów API. Podstawowa funkcjonalność UIKit nie uległa zmianie. Odnosi się to do zdecydowanej większości platform iOS SDK.

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

Jeśli masz problemy init(coder:), zapoznaj się z odpowiedzią EridB .

akashivskyy
źródło
3
Możesz nawet pominąć ;! ;) Czy miałbyś coś przeciwko opracowaniu as UIViewController? Dlaczego to konieczne?
Sebastian Wramba
5
assłowo kluczowe służy do rzutowania czcionek. Jest taki sam jak (UIViewController *)anObjectw celu c
Garoal
1
Tak, wiem, że mogę je pominąć, ale to część długiego nawyku. : D Jako instantiateViewControllerWithIdentifierzwroty AnyObject( idrównoważne w Swift) i deklaruję vcjako UIViewController, muszę typecast AnyObjectdo UIViewController.
akashivskyy
Cześć przyjaciele, mam do czynienia z innym problemem, ten kod działa na symulatorze, a nie na moim iPadzie 2, który ma iOS 7.1.2. Jeśli nie masz nic przeciwko, pomóż mi rozwiązać ten problem.
Indra
3
@akashivskyy Zdecydowanie dla ciebie. Ale może nie dla niektórych.
mmc
43

Dla osób używających odpowiedzi @ akashivskyy do tworzenia wystąpienia UIViewControlleri mają wyjątek:

błąd krytyczny: użycie niezaimplementowanego inicjatora „init (koder :)” dla klasy

Szybka wskazówka:

Ręcznie zaimplementuj required init?(coder aDecoder: NSCoder)w miejscu docelowym UIViewController, który próbujesz utworzyć

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

Jeśli potrzebujesz więcej opisu, zapoznaj się z moją odpowiedzią tutaj

E-Riddie
źródło
Jeśli chcesz użyć niestandardowego inicjatora, możesz po prostu wywołać super za pomocą super.init (nibName: nil, bundle: nil), a whew ładuje się dobrze lub wywołać go z nazwą pliku NIB.
user1700737
4
@ user1700737 Tworzę instancję viewController odnoszącą się do scenorysu, który wykonuje initWithCoder, a nie initWithNib. Zobacz to pytanie stackoverflow.com/questions/24036393/…
E-Riddie
Cześć przyjaciele, mam do czynienia z innym problemem, ten kod działa na symulatorze, a nie na moim iPadzie 2, który ma iOS 7.1.2. Jeśli nie masz nic przeciwko, pomóż mi rozwiązać ten problem.
Indra
@Indra, musisz zadać kolejne pytanie na stosie, podaj mi link Z przyjemnością Ci pomogę!
E-Riddie
W Swift 1.2 musisz wprowadzić init(coder aDecoder: NSCoder!)„wymagane”. Więc teraz musisz napisać:required init(coder aDecoder: NSCoder!)
Eduardo Viegas,
18

Ten link ma obie implementacje:

Szybki:

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

Cel C

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

Ten link zawiera kod do inicjowania kontrolera widoku w tej samej serii ujęć

/*
 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
źródło
15

Odpowiedź akashivskyy działa dobrze! Ale w przypadku problemów z powrotem z prezentowanego kontrolera widoku, ta alternatywa może być pomocna. To zadziałało dla mnie!

Szybki:

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
źródło
12

Zaktualizowany kod Swift 4.2 to

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

To działało dobrze dla mnie, gdy umieściłem go w AppDelegate

Maxxafari
źródło
7

Jeśli chcesz to przedstawić modalnie, powinieneś mieć coś w stylu:

let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewControllerID")
self.showDetailViewController(vc as! YourViewControllerClassName, sender: self)
Hamid
źródło
5

Chciałbym zaproponować znacznie czystszy sposób. Będzie to przydatne, gdy mamy wiele scenariuszy

1. Utwórz strukturę ze wszystkich swoich scenariuszy

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

2. Utwórz takie rozszerzenie UIStoryboard

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

Podaj identyfikator serii ujęć jako nazwę klasy i użyj poniższego kodu do utworzenia wystąpienia

let loginVc = UIStoryboard.login.instantiateViewController(withIdentifier: "\(LoginViewController.self)") as! LoginViewController
vijeesh
źródło
Po co @nonobjc?
StackRunner
1
@StackRunner nie będzie dostępny dla celu c
XcodeNOOB,
3

Swift 4:

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let yourVC: YourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as! YourVC
rysował..
źródło
2

Jeśli masz Viewcontroller nieużywający żadnej scenorysu / Xib, możesz przejść do tego konkretnego VC, jak poniżej:

 let vcInstance : UIViewController   = yourViewController()
 self.present(vcInstance, animated: true, completion: nil)
Aks
źródło
Rozumiem: „nie można zbudować, ponieważ nie ma dostępnych inicjatorów”.
Paul Bénéteau,
rynki zbytu i inne relacje nawiązane przez scenorys zostały utracone
jose920405
2

Szybki 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
źródło
1

Wiem, że to stary wątek, ale myślę, że obecne rozwiązanie (użycie zakodowanego identyfikatora ciągu dla danego kontrolera widoku) jest bardzo podatne na błędy.

Stworzyłem skrypt czasu kompilacji (do którego można uzyskać dostęp tutaj ), który stworzy bezpieczny sposób kompilatora do uzyskiwania dostępu i tworzenia instancji kontrolerów widoku ze wszystkich scenariuszy w ramach danego projektu.

Na przykład kontroler widoku o nazwie vc1 w Main.storyboard zostanie utworzony w następujący sposób:

let vc: UIViewController = R.storyboard.Main.vc1^  // where the '^' character initialize the controller
Nadav96
źródło
1

Bez względu na to, co próbowałem, to po prostu nie działałoby dla mnie - żadnych błędów, ale też żadnego nowego kontrolera widoku na moim ekranie. Nie wiem dlaczego, ale zawinięcie go w funkcję limitu czasu w końcu sprawiło, że działało:

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
źródło
1

Szybki 5

let vc = self.storyboard!.instantiateViewController(withIdentifier: "CVIdentifier")
self.present(vc, animated: true, completion: nil)
Binoy Jose
źródło