簡體   English   中英

Storyboard - 參考 AppDelegate 中的 ViewController

[英]Storyboard - refer to ViewController in AppDelegate

考慮以下場景:我有一個基於故事板的應用程序。 我將一個 ViewController 對象添加到故事板,將這個 ViewController 的類文件添加到項目中,並在 IB 身份檢查器中指定新類的名稱。 現在我將如何從 AppDelegate 以編程方式引用這個 ViewController? 我已經使用相關類創建了一個變量並將其轉換為 IBOutlet 屬性,但是我沒有看到任何能夠在代碼中引用新 ViewController 的方法 - 任何按住 ctrl 並拖動連接的嘗試都不起作用.

即在 AppDelegate 中,我可以像這樣訪問基本的 ViewController

(MyViewController*) self.window.rootViewController

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

查看-[UIStoryboard instantiateViewControllerWithIdentifier:]文檔 這允許您使用您在 IB 屬性檢查器中設置的標識符從故事板實例化視圖控制器:

在此處輸入圖片說明

編輯添加示例代碼:

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

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

如果您使用XCode 5,則應該以不同的方式進行。

  • UIStoryboard選擇你的UIViewController
  • 轉到右上角的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;

通常,系統應該使用故事板處理視圖控制器實例化。 你需要的是通過抓取到的引用遍歷的viewController層次self.window.rootViewController而不是初始化視圖控制器,它應該,如果你已經設置你的故事板已經正確正確初始化。

所以,假設你的rootViewController是一個 UINavigationController,然后你想向它的頂視圖控制器發送一些東西,你可以在你的 AppDelegate 的didFinishLaunchingWithOptions這樣做:

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

在 Swift 中 if 會非常相似:

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

您真的不應該使用來自應用程序委托的故事板 ID 來初始化視圖控制器,除非您想繞過加載故事板的正常方式並自己加載整個故事板。 如果您必須從 AppDelegate 初始化場景,那么您很可能做錯了什么。 我的意思是假設您出於某種原因想要將數據發送到堆棧下方的視圖控制器,AppDelegate 不應該進入視圖控制器堆棧以設置數據。 那不是它的事。 它的業務是 rootViewController。 讓 rootViewController 處理它自己的孩子! 因此,如果我通過刪除 info.plist 文件中對它的引用來繞過系統的正常故事板加載過程,我最多會使用instantiateViewControllerWithIdentifier:實例化 rootViewController ,如果它是一個容器,則可能是它的根,如 UINavigationController . 你想要避免的是實例化已經被故事板實例化的視圖控制器。 這是我經常看到的一個問題。 簡而言之,我不同意接受的答案。 這是不正確的,除非海報意味着從 info.plist 中刪除故事板的加載,否則你將加載 2 個故事板,這是沒有意義的。 這可能不是內存泄漏,因為系統初始化了根場景並將其分配給了窗口,但隨后您又出現並再次實例化並再次分配了它。 您的應用開局非常糟糕!

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

適用於 iOS 13+

在場景委托中:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM