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?

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 .


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


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)

}

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

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)

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


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)

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

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

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)

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: {

})

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

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

1

Szybki 5

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.