故事板 - 参考AppDelegate中的ViewController

Mat*_*s D 122 iphone objective-c storyboard uiviewcontroller ios

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

即在AppDelegate中我可以像这样到达基本的ViewController

(MyViewController*) self.window.rootViewController
Run Code Online (Sandbox Code Playgroud)

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

Rob*_*ill 165

看一看的文档进行-[UIStoryboard instantiateViewControllerWithIdentifier:].这允许您使用在IB Attributes Inspector中设置的标识符从故事板中实例化视图控制器:

在此输入图像描述

已编辑以添加示例代码:

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

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];
Run Code Online (Sandbox Code Playgroud)

  • 如果您正在制作通用应用程序,请确保使用MainStoryboard_iPhone/MainStoryboard_iPad,否则您将崩溃. (24认同)
  • 在委托中,您可以访问info.plist加载的故事板实例,如下所示:`[[[window] rootViewController] storyboard]`根据文档,这将返回"视图控制器所源自的故事板".(或_nil_如果它不是来自故事板).从那个UIStoryboard*你可以使用@RobinSummerhill提到的实例化调用.请注意,Storyboards会根据需要实例化viewControllers(_scenes_)的新实例,并且不会重复使用之前查看过的实例. (16认同)
  • 在Xcode 5中,标识符称为Storyboard ID (10认同)
  • 我相信OP想要知道如何获得当前运行的vc.不是如何加载一个.正如他解释的那样,你曾经能够说出这个**self.window.rootViewController**现在你已经不能了. (6认同)

Far*_*tas 41

如果你使用XCode5,你应该以不同的方式.

  • 选择你UIViewControllerUIStoryboard
  • 转到Identity Inspector右侧顶部窗格
  • 选中Use Storyboard ID复选框
  • 为该Storyboard ID字段写一个唯一的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;
Run Code Online (Sandbox Code Playgroud)

  • 据我所知并且能够尝试一下,__这是更新的答案. (4认同)

smi*_*Bot 8

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

所以,假设你rootViewController是一个UINavigationController,然后你想向它的顶级视图控制器发送一些东西,你可以在你的AppDelegate中这样做didFinishLaunchingWithOptions:

UINavigationController *nav = (UINavigationController *) self.window.rootViewController;
MyViewController *myVC = (MyViewController *)nav.topViewController;
myVC.data = self.data;
Run Code Online (Sandbox Code Playgroud)

在Swift中如果非常相似:

let nav = self.window.rootViewController as! UINavigationController;
let myVC = nav.topViewController as! MyViewController
myVc.data = self.data
Run Code Online (Sandbox Code Playgroud)

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