故事板-请参阅AppDelegate中的ViewController


122

请考虑以下情形:我有一个基于情节提要的应用程序。我将一个ViewController对象添加到情节提要中,将此ViewController的类文件添加到项目中,并在IB身份检查器中指定新类的名称。现在,我该如何从AppDelegate以编程方式引用此ViewController?我已经在相关类中创建了一个变量,并将其转换为IBOutlet属性,但是我看不到任何能够在代码中引用新ViewController的方法-按住ctrl拖动连接的任何尝试均无效。

即在AppDelegate中,我可以像这样进入基本的ViewController

(MyViewController*) self.window.rootViewController

但是情节提要中包含的其他ViewController呢?


检查此答案。速度很快,但语言相似。
Borzh

Answers:


165

看一看的文档进行-[UIStoryboard instantiateViewControllerWithIdentifier:]。这使您可以使用在IB属性检查器中设置的标识符从情节提要板实例化视图控制器:

在此处输入图片说明

编辑以添加示例代码:

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

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

罗宾,您好,谢谢!我看了一下这份文件,但实例化和初始化一词混在一起了……这使我们到达那里(按照您的指示进行:)(该死的答复中缺少代码格式……)UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName:@ “ MainStoryboard”捆绑包:nil]; MyViewController * thisController =(MyViewController *)[mainStoryboard InstantiateViewControllerWithIdentifier:@“ myvc”];
Matthias D

我已将您的示例代码添加到答案中,并为所有正在查看此格式的人提供了格式设置。
罗宾·萨默希尔

24
如果您要制作通用应用,请确保使用MainStoryboard_iPhone / MainStoryboard_iPad,否则会崩溃。
roocell 2011年

16
在委托中,您可以像这样访问由info.plist加载的故事板实例:[[[self window] rootViewController] storyboard] 根据文档,这将返回“视图控制器所源自的故事板”。(如果不是来自故事板,则为nil)。从该UIStoryboard *中,您可以使用@RobinSummerhill提到的实例化调用。请注意,情节提要根据需要实例化viewControllers(场景)的新实例,并且不会重复使用以前查看过的实例。
塔德·布姆克罗

6
我相信OP希望知道如何获取当前正在运行的vc。不是怎么装一个。就像他解释的那样,您以前可以说出self.window.rootViewController,现在您再也不能说了。
Fattie 2014年

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;

4
据我所知并能够尝试,是更新的答案。
gnclmorais 2013年

情节提要的名称是其文件名,不带扩展名,因此,如果您以这种方式设置项目,则它也可以是“ Main_iPhone”或“ Main_iPad”。
布莱恩·怀特

然后在登录后如何过渡回原始的rootViewController。至少就我对iOS 7和Xcode 5.0.2的了解而言-更改根视图控制器将立即生效,并且无需动画即可切换视图层次结构。UX团队以更少的代价谋杀了编码人员。
大声笑

我将如何使用Swift做到这一点?
Leo Dabus 2014年

8

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

因此,假设您rootViewController是一个UINavigationController,然后要将某些内容发送到其顶部视图控制器,则可以在AppDelegate的控件中执行以下操作didFinishLaunchingWithOptions

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

在Swift中,如果非常相似:

let nav = self.window.rootViewController as! UINavigationController;
let myVC = nav.topViewController as! MyViewController
myVc.data = self.data

除非您要绕过加载故事板的正常方式并自己加载整个故事板,否则您实际上不应该使用应用程序委托中的故事板ID初始化视图控制器。如果您必须通过AppDelegate初始化场景,则很可能在做一些错误的事情。我的意思是想象一下,由于某种原因,您想将数据发送到堆栈中的视图控制器,AppDelegate不应进入视图控制器堆栈以设置数据。那不是它的事。它的业务是rootViewController。让rootViewController处理自己的孩子!因此,如果我通过在info.plist文件中删除对其进行的引用来绕过系统正常的情节提要加载过程,则最多使用以下方法实例化rootViewController:instantiateViewControllerWithIdentifier:,如果是容器,例如UINavigationController,则可能是其根。您要避免的是实例化已由情节提要实例化的视图控制器。我看到的这个问题很多。简而言之,我不同意接受的答案。除非张贴者打算从info.plist中删除故事板的加载,否则这是不正确的,因为否则您将加载2个故事板,这是没有意义的。可能不是内存泄漏,因为系统初始化了根场景并将其分配给窗口,但是随后您又来实例化它并再次分配它。您的应用程序开局非常糟糕!


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.