在Swift中实例化并呈现一个视图控制器

351

问题

我开始学习 Swift 编程语言,但是在从特定的 UIStoryboard 初始化 UIViewController 的时候,我无法正确地进行输入。

Objective-C 中,我只需要写:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"StoryboardName" bundle:nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"ViewControllerID"];
[self presentViewController:viewController animated:YES completion:nil];

有谁可以帮我学习如何在Swift中实现这个功能吗?

18个回答

743

这篇答案最后更新于Swift 5.4和iOS 14.5 SDK。


这只涉及到新语法和轻微修改的API。UIKit的基本功能没有变化。对于大多数iOS SDK框架也是如此。

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

请确保在“Storyboard ID”下设置故事板中的myVCID


3
甚至可以省略分号! ;) 你介意详细解释一下 as UIViewController 的作用吗?这个是为什么必要的? - Sebastian Wramba
5
as关键字用于类型转换。这与Objective-C中的(UIViewController *)anObject相同。 - Garoal
1
是的,我知道我可以省略它们,但那是长期习惯的一部分。 :D 因为 instantiateViewControllerWithIdentifier 返回 AnyObject(在 Swift 中相当于 id),而我将 vc 声明为 UIViewController,所以我必须将 AnyObject 强制转换为 UIViewController - akashivskyy
大家好,我遇到了一些问题。这段代码在模拟器上可以运行,但是在我的iOS v7.1.2版本的iPad2上无法运行。如果您不介意,请帮助我解决这个问题。 - Indra
3
当然,对于你来说是这样。但对于某些人可能不是。 - mmc
显示剩余13条评论

45

对于那些使用@akashivskyy的答案来实例化UIViewController,并且遇到以下异常:

致命错误:类“XXX”的未实现的初始化程序“init(coder:)”的使用

快速提示:

在您要实例化的目标UIViewController中手动实现required init?(coder aDecoder: NSCoder)

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
如果您需要更多描述,请参考我在这里的回答。

如果你想使用自定义的初始化器,你可以调用 super.init(nibName: nil, bundle: nil) ,这样视图将可以正常加载;或者你也可以传入 NIB 文件的名称进行调用。 - Lars Christoffersen
4
@user1700737 我正在使用故事板引用实例化viewController,它执行的是initWithCoder而不是initWithNib。请参考这个问题https://dev59.com/J2Ag5IYBdhLWcg3wDHQ3#24036440 - E-Riddie
大家好,我遇到了一些问题。这段代码在模拟器上可以运行,但是在我的iOS v7.1.2版本的iPad2上无法运行。如果您不介意,请帮助我解决这个问题。 - Indra
@Indra,你需要在Stack上提出另一个问题,给我链接,我很乐意帮助你! - E-Riddie
在Swift 1.2中,您必须将init(coder aDecoder: NSCoder!)“required”(必要)。因此现在您必须编写以下内容:required init(coder aDecoder: NSCoder!) - Eduardo Viegas

20

此链接包含两种实现方案:

Swift:

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

Objective 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

akashivskyy的答案完全有效!但是,如果你在返回所呈现的视图控制器时遇到问题,这个替代方法可能会有帮助。它对我很有效!

Swift:


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)

Obj-C:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MyStoryboardName" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"someViewController"];
[self.navigationController showViewController:vc sender:nil];

14

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
我想建议一种更清晰的方法。当我们有多个故事板时,这将非常有用。
1.创建一个包含所有故事板的结构。
struct Storyboard {
      static let main = "Main"
      static let login = "login"
      static let profile = "profile" 
      static let home = "home"
    }

创建一个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 这将不可用于 Objective-C。 - XcodeNOOB

7
如果您想以模态方式呈现它,应该像下面这样做:
let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewControllerID")
self.showDetailViewController(vc as! YourViewControllerClassName, sender: self)

5
无论我尝试什么,它都不起作用 - 没有错误,但屏幕上也没有新的视图控制器。不知道为什么,但将其包装在超时函数中最终使其工作:
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)
}

3

Swift 4:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接