Создание и представление viewController в Swift
вопрос
Я начал смотреть на новый 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?
18 ответов
Все дело в новом синтаксисе, функциональность которого не изменилась:
// Swift 3.0
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "someViewController")
self.present(controller, animated: true, completion: nil)
Если у вас проблемы с init(coder:)
пожалуйста, обратитесь к ответу EridB.
Для людей, использующих ответ @akashivskyy для создания экземпляра UIViewController
и имеют исключение:
фатальная ошибка: использование не реализованного инициализатора 'init(coder:)' для класса
Быстрая подсказка:
Внедрить вручную required init?(coder aDecoder: NSCoder)
в вашем пункте назначения UIViewController
что вы пытаетесь создать экземпляр
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Если вам нужно больше описания, пожалуйста, обратитесь к моему ответу здесь
Эта ссылка имеет обе реализации:
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)
}
Ответ акашивского работает просто отлично! Но, если у вас возникли проблемы с возвратом из представленного контроллера представления, эта альтернатива может быть полезна. Это сработало для меня!
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];
Swift 4.2 обновил код
let storyboard = UIStoryboard(name: "StoryboardNameHere", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.present(controller, animated: true, completion: nil)
Если вы хотите представить это модально, у вас должно быть что-то вроде ниже:
let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewControllerID")
self.showDetailViewController(vc as! YourViewControllerClassName, sender: self)
Я хотел бы предложить гораздо более чистый способ. Это будет полезно, когда у нас есть несколько раскадровок
1. Создайте структуру со всеми вашими раскадровками
struct Storyboard {
static let main = "Main"
static let journey = "login"
static let journey = "profile"
static let journey = "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
// "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
Неважно, что я пытался, это просто не сработало бы для меня - без ошибок, но и без нового контроллера просмотра на моем экране. Не знаю почему, но обертывание в функции тайм-аута, наконец, заставило его работать:
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)
}
Свифт 4:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let yourVC: YourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as! YourVC
Свифт 3
let settingStoryboard : UIStoryboard = UIStoryboard(name: "SettingViewController", bundle: nil)
let settingVC = settingStoryboard.instantiateViewController(withIdentifier: "SettingViewController") as! SettingViewController
self.present(settingVC, animated: true, completion: {
})
Если у вас есть Viewcontroller, не использующий раскадровку /Xib, вы можете перейти к этому конкретному VC, как показано ниже:
let vcInstance : UIViewController = yourViewController()
self.present(vcInstance, animated: true, completion: nil)
Swift 5
let vc = self.storyboard!.instantiateViewController(withIdentifier: "CVIdentifier")
self.present(vc, animated: true, completion: nil)
Я знаю, что это старый поток, но я думаю, что текущее решение (использующее жестко закодированный идентификатор строки для данного контроллера представления) очень подвержено ошибкам.
Я создал сценарий времени сборки ( доступ к которому вы можете получить здесь), который создаст безопасный способ компилятора для доступа и создания экземпляров контроллеров представления со всей раскадровки в данном проекте.
Например, будет создан экземпляр контроллера представления с именем vc1 в Main.storyboard следующим образом:
let vc: UIViewController = R.storyboard.Main.vc1^ // where the '^' character initialize the controller
Я использую этот помощник:
struct Storyboard<T: UIViewController> {
static var storyboardName: String {
return String(describing: T.self)
}
static var viewController: T {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: Self.storyboardName) as? T else {
fatalError("Could not get controller from Storyboard: \(Self.storyboardName)")
}
return vc
}
}
Использование (идентификатор раскадровки должен соответствовать имени класса UIViewController)
let myVC = Storyboard.viewController as MyViewController
guard let vc = storyboard?.instantiateViewController(withIdentifier: "add") else { return }
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true, completion: nil)
if let destinationVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DestinationVC") as? DestinationVC{
let nav = self.navigationController
//presenting
nav?.present(destinationVC, animated: true, completion: {
})
//push
nav?.pushViewController(destinationVC, animated: true)
}
Я создал библиотеку, которая будет обрабатывать это намного проще с лучшим синтаксисом:
https://github.com/Jasperav/Storyboardable
Просто измените Storyboard.swift и позвольте ViewControllers
соответствовать Storyboardable
,