如何在代码中从类加载故事板?

192

我的问题是我想要同时使用storyboardxib,但我找不到合适的方法来编程加载和显示storyboard。该项目最初是使用xib进行开发的,现在很难将所有xib文件嵌套在storyboard中。因此,我正在寻找一种通过代码完成它的方法,例如视图控制器的alloc、init、push。在我的情况下,storyboard中只有一个控制器:UITableViewController,其中包含静态单元格和我想要显示的一些内容。如果有人知道在不进行大量重构的情况下同时使用xib和storyboard的正确方法,我将非常感激帮助。

8个回答

386

在你的Storyboard中,进入属性检查器并设置视图控制器的标识符。然后,可以使用以下代码呈现该视图控制器。

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:@"myViewController"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];

67
如果你想要启动场景的默认视图控制器,[sb instantiateInitialViewController] 是一个方便的方法。 - drewish
James,谢谢!我已经搜索了相当长的时间,试图弄清楚如何实例化Storyboard的视图。找到你的答案(以及kokoko的问题)真是太令人耳目一新了。 - Jonathan Beebe
在James Beith的代码中,如果当前视图控制器与UIViewControler *vc来回切换,则必须重复使用它。我通过艰难的方式发现,vc会一直保留并连接到故事板nib,直到用户在新视图上按下按钮,这将导致该代码之前版本中已弃用的vc存在内存泄漏问题。 - SWoo
13
如果有人想知道如何在应用程序委托中执行此操作,您可以按以下顺序使用以下行替换“[self presentViewcontroller]”逻辑:1)self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 2)self.window.rootViewController = vc; 并且3)[self.window makeKeyAndVisible];。因为这不是从应用程序委托的模态转换,所以您还可以去掉modalTransitionStyle行。 - lewiguez
如何调用Cocoa Touch类文件以实现ViewController功能。 - Ephrim Daniel
显示剩余2条评论

86

Swift 3

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "viewController")
self.navigationController!.pushViewController(vc, animated: true)

Swift 2

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController")
self.navigationController!.pushViewController(vc, animated: true)

先决条件

给您的视图控制器分配一个Storyboard ID

故事板ID

IB > 显示 Identity inspector > Identity > Storyboard ID

Swift(旧版)

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController") as? UIViewController
self.navigationController!.pushViewController(vc!, animated: true)

编辑:根据Fred A.的评论,建议使用Swift 2。

如果你想在没有任何导航控制器的情况下使用,你必须像下面这样使用:

    let Storyboard  = UIStoryboard(name: "Main", bundle: nil)
    let vc = Storyboard.instantiateViewController(withIdentifier: "viewController")
    present(vc , animated: true , completion: nil)

1
在Swift 2中,您不需要添加"as? UIViewController",编译器会自动确定它。 - Frederic Adda
2
你可以直接使用 self.storyboard 并合并第一行和第二行。 - mfaani

18

在属性检查器中为该视图控制器提供标识符,下面的代码对我有效。

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
DetailViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"DetailViewController"];
[self.navigationController pushViewController:detailViewController animated:YES];

5

试试这个

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:@"Login"];

[[UIApplication sharedApplication].keyWindow setRootViewController:vc];

如果您没有像其他答案中所示使用UINavigationController,则可以使用此选项。 - latenitecoder

2

对于 Swift 4和5,您可以这样做。良好的实践是将Storyboard的名称设置为StoryboardID。

enum StoryBoardName{
   case second = "SecondViewController"
}
extension UIStoryboard{
   class func load(_ storyboard: StoryBoardName) -> UIViewController{
      return UIStoryboard(name: storyboard.rawValue, bundle: nil).instantiateViewController(withIdentifier: storyboard.rawValue)
   }
}

然后,您可以像这样在您的 ViewController 中加载您的 Storyboard:

class MyViewController: UIViewController{
     override func viewDidLoad() {
        super.viewDidLoad()
        guard let vc = UIStoryboard.load(.second) as? SecondViewController else {return}
        self.present(vc, animated: true, completion: nil)
     }

当您创建一个新的Storyboard时,只需在StoryboardID上设置相同的名称,并将Storyboard名称添加到枚举“StoryBoardName”中即可。


2

在Swift中,你可以用以下方式替换NavigationControllerpushController

present(vc, animated:true , completion: nil)

1
您可以随时跳转到根控制器:

UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateInitialViewController];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];

1
下面的扩展将允许您加载一个Storyboard及其相关的UIViewController。例如:如果您有一个名为ModalAlertViewControllerUIViewController和一个名为“ModalAlert”的故事板。
let vc: ModalAlertViewController = UIViewController.loadStoryboard("ModalAlert")

将同时加载StoryboardUIViewController,并且vc的类型将为ModalAlertViewController注意假定故事板的故事板ID与故事板名称相同,并且该故事板已标记为Is Initial View Controller

extension UIViewController {
    /// Loads a `UIViewController` of type `T` with storyboard. Assumes that the storyboards Storyboard ID has the same name as the storyboard and that the storyboard has been marked as Is Initial View Controller.
    /// - Parameter storyboardName: Name of the storyboard without .xib/nib suffix.
    static func loadStoryboard<T: UIViewController>(_ storyboardName: String) -> T? {
        let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
        if let vc = storyboard.instantiateViewController(withIdentifier: storyboardName) as? T {
            vc.loadViewIfNeeded() // ensures vc.view is loaded before returning
            return vc
        }
        return nil
    }
}

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