Создание и представление viewController в Swift


300

вопрос

Я начал принимать вид нового SwiftПО Xcode 6, и я попробовал некоторые демонстрационные проекты и обучающие программы . Теперь я застрял в:

Создание и представление viewControllerиз определенной раскадровки

Решение Objective-C

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

Как этого добиться на Swift?

Ответы:


648

Этот ответ был последний раз пересмотрен для Swift 5.2 и iOS 13.4 SDK.


Все дело в новом синтаксисе и немного пересмотренных API. Базовая функциональность UIKit не изменилась. Это верно для подавляющего большинства каркасов iOS SDK.

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

Если у вас возникли проблемы init(coder:), обратитесь к ответу EridB .


3
Вы даже можете опустить ;! ;) Не могли бы вы остановиться на этом as UIViewController? Почему это необходимо?
Себастьян Врамба

5
asключевое слово используется для приведения типов. Это так же, как (UIViewController *)anObjectв объективе c
Garoal

1
Да, я знаю, что могу их опустить, но это часть долгой привычки. : D Как instantiateViewControllerWithIdentifierвозвращает AnyObject( idэквивалент в Swift), и я объявляю vcкак UIViewController, я должен тип AnyObjectк UIViewController.
Акашивский

Привет друзья, я столкнулся с некоторой другой проблемой, этот код работает на симуляторе, а не на моем ipad2, который имеет iOS v7.1.2 Если вы не возражаете, помогите мне решить эту проблему.
Индра

3
@akashivskyy Совершенно определенно для вас. Но, возможно, не для некоторых.
mmc

43

Для людей, использующих ответ @ akashivskyy для создания экземпляра UIViewControllerи имеющих исключение:

фатальная ошибка: использование не реализованного инициализатора 'init (coder :)' для класса

Быстрая подсказка:

Вручную реализовать required init?(coder aDecoder: NSCoder)в пункте назначения UIViewControllerто, что вы пытаетесь создать

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

Если вам нужно больше описания, пожалуйста, обратитесь к моему ответу здесь


Если вы хотите использовать пользовательский инициатор, вы можете просто вызвать super с помощью super.init (nibName: nil, bundle: nil), и файл будет загружен нормально или вызовет его с именем NIB-файла.
user1700737

4
@ user1700737 Я создаю экземпляр viewController со ссылкой на раскадровку, которая выполняет initWithCoder, а не initWithNib. Обратитесь к этому вопросу stackoverflow.com/questions/24036393/…
E-Riddie

Привет друзья, я столкнулся с некоторой другой проблемой, этот код работает на симуляторе, а не на моем ipad2, который имеет iOS v7.1.2 Если вы не возражаете, помогите мне решить эту проблему.
Индра

@Indra вам нужно задать еще один вопрос в стеке, дайте мне ссылку, я буду рад помочь вам!
E-Riddie

На Swift 1.2 вы должны сделать init(coder aDecoder: NSCoder!)«обязательно». Итак, теперь вы должны написать следующее:required init(coder aDecoder: NSCoder!)
Эдуардо Виегас

18

Эта ссылка имеет обе реализации:

Swift:

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

Цель С

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

Эта ссылка содержит код для запуска viewcontroller в той же раскадровке

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

ответ акашивского работает просто отлично! Но, если у вас возникли проблемы с возвратом из представленного контроллера представления, эта альтернатива может быть полезна. Это сработало для меня!

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

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)

Это работало хорошо для меня, когда я положил его в AppDelegate


7

Если вы хотите представить это модально, у вас должно быть что-то вроде ниже:

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

5

Я хотел бы предложить гораздо более чистый способ. Это будет полезно, когда у нас есть несколько раскадровок

1. Создайте структуру со всеми вашими раскадровками

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

2. Создайте расширение 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)
  }
}

Укажите идентификатор раскадровки в качестве имени класса и используйте приведенный ниже код для создания экземпляра.

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

Для чего @nonobjc?
StackRunner

1
@StackRunner это не будет доступно для цели c
XcodeNOOB

3

Свифт 4:

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

2

Если у вас есть Viewcontroller, не использующий раскадровку / Xib, вы можете перейти к этому конкретному VC, как показано ниже:

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

Я получаю это: «не может быть построено, потому что у него нет доступных инициализаторов».
Поль Бенето

розетки и другие отношения, созданные раскадровкой, потеряны
jose920405

2

Свифт 3 Раскадровка

let settingStoryboard : UIStoryboard = UIStoryboard(name: "SettingViewController", bundle: nil)
let settingVC = settingStoryboard.instantiateViewController(withIdentifier: "SettingViewController") as! SettingViewController
self.present(settingVC, animated: true, completion: {

})

1

Я знаю, что это старый поток, но я думаю, что текущее решение (использующее жестко закодированный идентификатор строки для данного контроллера представления) очень подвержено ошибкам.

Я создал сценарий времени сборки ( доступ к которому вы можете получить здесь ), который создаст безопасный способ компилятора для доступа и создания экземпляров контроллеров представления со всей раскадровки в данном проекте.

Например, контроллер вида с именем vc1 в Main.storyboard будет создан следующим образом:

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

1

Неважно, что я пытался, это просто не сработало бы для меня - без ошибок, но и без нового контроллера просмотра на моем экране. Не знаю почему, но обертывание в функции тайм-аута, наконец, заставило его работать:

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


0

Я создал библиотеку, которая будет обрабатывать это намного проще с лучшим синтаксисом:

https://github.com/Jasperav/Storyboardable

Просто измените Storyboard.swift и позвольте ViewControllersсоответствовать Storyboardable.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.