故事板 - 参考AppDelegate中的ViewController

时间:2011-11-18 17:24:53

标签: iphone objective-c ios uiviewcontroller storyboard

考虑以下场景:我有一个基于故事板的应用程序。我将一个ViewController对象添加到storyboard中,将此ViewController的类文件添加到项目中,并在IB身份检查器中指定新类的名称。现在我将如何从AppDelegate以编程方式引用此ViewController?我已经使用相关类创建了一个变量并将其转换为IBOutlet属性,但我没有看到任何能够在代码中引用新的ViewController的方法 - 任何尝试按住Ctrl键拖动连接都不起作用

即。在AppDelegate中我可以像这样

到达基础ViewController
(MyViewController*) self.window.rootViewController

但是故事板中包含的任何其他ViewController怎么样?

5 个答案:

答案 0 :(得分:165)

查看-[UIStoryboard instantiateViewControllerWithIdentifier:]的{​​{3}}。这允许您使用在IB Attributes Inspector中设置的标识符从故事板中实例化视图控制器:

enter image description here

已编辑以添加示例代码:

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                         bundle: nil];

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];

答案 1 :(得分:38)

如果你使用XCode 5,你应该以不同的方式进行。

  • UIViewController
  • 中选择UIStoryboard
  • 转到右侧顶部窗格的Identity Inspector
  • 选中Use Storyboard ID复选框
  • 将唯一ID写入Storyboard ID字段

然后编写代码。

// Override point for customization after application launch.

if (<your implementation>) {
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" 
                                                             bundle: nil];
    YourViewController *yourController = (YourViewController *)[mainStoryboard 
      instantiateViewControllerWithIdentifier:@"YourViewControllerID"];
    self.window.rootViewController = yourController;
}

return YES;

答案 2 :(得分:8)

通常,系统应该使用故事板处理视图控制器实例化。你想要的是通过获取self.window.rootViewController的引用来遍历viewController层次结构,而不是初始化视图控制器,如果你已经正确设置了故事板,那么它应该已经正确初始化了。

所以,让我们说你的rootViewController是一个UINavigationController,然后你想向它的顶级视图控制器发送一些内容,你可以在你的AppDelegate {{1}中这样做}:

didFinishLaunchingWithOptions

在Swift中如果非常相似:

UINavigationController *nav = (UINavigationController *) self.window.rootViewController;
MyViewController *myVC = (MyViewController *)nav.topViewController;
myVC.data = self.data;

除非您想绕过故事板加载的正常方式并自己加载整个故事板,否则您不应该使用应用程序委托中的故事板ID来初始化视图控制器。如果您不得不从AppDelegate初始化场景,那么您最有可能做错了什么。我的意思是想象一下,出于某种原因,你希望将数据发送到堆栈中的视图控制器,AppDelegate不应该进入视图控制器堆栈来设置数据。这不是它的业务。它的业务是rootViewController。让rootViewController处理自己的子节点!所以,如果我通过删除info.plist文件中对它的引用来绕过系统正常的故事板加载过程,我最多会使用let nav = self.window.rootViewController as! UINavigationController; let myVC = nav.topViewController as! MyViewController myVc.data = self.data 实例化rootViewController,如果是容器则可能是root用户,像一个UINavigationController。您要避免的是实例化已经由故事板实例化的视图控制器。这是我看到的很多问题。简而言之,我不同意接受的答案。这是不正确的,除非海报意味着从info.plist删除故事板的加载,因为你将加载2个故事板,否则没有意义。它可能不是内存泄漏,因为系统初始化了根场景并将其分配给窗口,但随后您又出现并再次实例化并再次分配它。你的应用程序开始非常糟糕!

答案 3 :(得分:0)

    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];

答案 4 :(得分:0)

对于iOS 13 +

在SceneDelegate中:

var window: UIWindow?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options 
connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    window = UIWindow(windowScene: windowScene)
    let storyboard = UIStoryboard(name: "Main", bundle: nil) // Where "Main" is the storyboard file name
    let vc = storyboard.instantiateViewController(withIdentifier: "ViewController") // Where "ViewController" is the ID of your viewController
    window?.rootViewController = vc
    window?.makeKeyAndVisible()
}