在Swift中实例化并呈现一个viewController


299

问题

我开始浏览上的新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上实现这一目标?

Answers:


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 2014年

1
是的,我知道我可以省略它们,但这只是长期习惯的一部分。:D As instantiateViewControllerWithIdentifier返回AnyObjectid在Swift中等效),我声明vcUIViewController,我必须强制转换AnyObjectUIViewController
akashivskyy 2014年

嗨,朋友们,我遇到了一些不同的问题,此代码在模拟器上而不是在具有iOS v7.1.2的ipad2上运行。如果您不介意,请帮助我解决此问题。
Indra 2014年

3
@akashivskyy最肯定的是,给你。但也许对某些人而言。
mmc 2014年

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)调用super,wew会很好地加载,或使用它们的NIB文件名来调用它。
user1700737 2014年

4
@ user1700737我正在实例化引用情节提要的viewController,该情节提要执行initWithCoder而不是initWithNib。请参考这个问题stackoverflow.com/questions/24036393/...
E-Riddie

嗨,朋友们,我遇到了一些不同的问题,此代码在模拟器上而不是在具有iOS v7.1.2的ipad2上运行。如果您不介意,请帮助我解决此问题。
Indra 2014年

@Indra您需要在栈上再问一个问题,给我链接我很高兴为您服务!
E-Riddie 2014年

在Swift 1.2上,您必须设置为init(coder aDecoder: NSCoder!)“ required”。因此,现在您必须编写以下内容:required init(coder aDecoder: NSCoder!)
Eduardo Viegas

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

此链接包含用于在同一情节提要中启动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

akashivskyy的答案很好!但是,如果您从显示的视图控制器返回时遇到麻烦,此替代方法可能会有所帮助。它为我工作!

迅速:

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)

对象:

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不使用任何Storyboard / Xib,则可以像下面的调用一样推送到该特定的VC:

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

我得到这样的信息:“由于没有可访问的初始化程序,因此无法构建”。
PaulBénéteau17年

情节
提要所引起

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

我知道这是一个旧线程,但是我认为当前的解决方案(对给定的视图控制器使用硬编码的字符串标识符)非常容易出错。

我已经创建了一个构建时间脚本(您可以在此处访问),它将创建一种编译器安全的方法,用于从给定项目中的所有故事板上访问和实例化视图控制器。

例如,名为视图控制器VC1Main.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)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.