Миттєве подання та подання представлення перегляду Контролер у Swift


299

Проблема

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

Миттєвий пошук, а потім подання viewControllerіз конкретної розкадровки

Об'єктивне-C рішення

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

Як цього досягти на Свіфті?

Відповіді:


647

Ця відповідь востаннє переглянута для 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.init (nibName: nil, bundle: nil), і whew буде добре завантажуватись або робити дзвінки з ім'ям файлу NIB.
користувач1700737

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

Це посилання має обидві реалізації:

Швидкий:

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

Мета C

UIViewController *viewController = [[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:@"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

відповідь акашівського працює просто чудово! Але, якщо у вас виникли проблеми із поверненням з представленого контролера перегляду, ця альтернатива може бути корисною. Це працювало для мене!

Швидкий:

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)

Я отримую це: "не може бути сконструйовано, оскільки він не має доступних ініціалізаторів".
Пол Бенето

торгові точки та інші стосунки, складені
розкладовою,

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

1

Швидкий 5

let vc = self.storyboard!.instantiateViewController(withIdentifier: "CVIdentifier")
self.present(vc, 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.