情节串连图板-请参考 App氏委托中的 ViewController

考虑下面的场景: 我有一个基于故事板的应用程序。我将一个 ViewController 对象添加到故事板中,将这个 ViewController 的类文件添加到项目中,并在 IB 标识检查器中指定新类的名称。现在,我要如何从应用委托程序化地引用这个 ViewController?我已经用相关类创建了一个变量,并将其转换为 IBOutlet 属性,但是我没有看到任何能够在代码中引用新 ViewController 的方法——任何试图 ctrl 拖动连接的尝试都不起作用。

也就是说,我可以像下面这样访问基本 ViewController

(MyViewController*) self.window.rootViewController

但是情节串连图板中包含的其他 ViewController 如何呢?

120009 次浏览

看看 documentation-[UIStoryboard instantiateViewControllerWithIdentifier:]。这允许您使用您在 IB 属性检查器中设置的标识符从情节串连板实例化视图控制器:

enter image description here

编辑添加示例代码:

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


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

如果你使用 XCode5,你应该用一种不同的方法。

  • UIStoryboard中选择 UIViewController
  • 转到右上方窗格上的 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;

Generally, the system should be handling view controller instantiation with a storyboard. What you want is to traverse the viewController hierarchy by grabbing a reference to the self.window.rootViewController as opposed to initializing view controllers, which should already be initialized correctly if you've setup your storyboard properly.

所以,假设你的 rootViewController是一个 UINavigationController,然后你想发送一些东西到它的 top view 控制器,你可以像这样在你的应用代理的 didFinishLaunchingWithOptions中做:

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

In Swift if would be very similar:

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

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

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

适用于 iOS13 +

场景代表:

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()
}