从 App Delegate (Swift) 调用 ViewControllers 方法或 Segue

Posted

技术标签:

【中文标题】从 App Delegate (Swift) 调用 ViewControllers 方法或 Segue【英文标题】:Call ViewControllers Method or Segue from App Delegate (Swift) 【发布时间】:2015-01-15 15:00:54 【问题描述】:

我创建了一个使用故事板的应用程序,并成功创建了一个可以正常工作的表格视图和详细信息页面。

我希望这样可以将滑动 localNotifications 的用户发送到应用内正确的详细信息页面。

看来我可以从 ViewController 调用函数,但是每当它们引用自己来更新任何细节或执行 segue 时,应用程序就会崩溃。

我的 ViewController 中的代码如下:

func handleMessageNotification (messageID:String)

    // this function should act as a conduit for the call from the delegate
    println("notif messageID: \(messageID)");
    self.performSegueWithIdentifier("showMessageDetail", sender: self);
    self.messageView.reloadData();

这是从我的 appDelegate 调用的

func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) 
  if (application.applicationState == UIApplicationState.Background || application.applicationState == UIApplicationState.Inactive)
    
        var rootViewController = self.window!.rootViewController
        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        var setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController") as ViewController
        rootViewController?.navigationController?.popToViewController(setViewController, animated: false)
        setViewController.handleMessageNotification(messageID);
  

println 工作正常,但 performSegue 失败(致命错误:在展开 Optional 值时意外发现 nil)并且 messageView.reload() 失败(同样的错误)。

如何在打开应用程序时收到通知以将应用程序触发到正确的位置?

这个解决方案“Get Instance Of ViewController From AppDelegate In Swift”使用了很多相同的方法,但我的解决方案不允许使用 ViewController 访问任何内容。

======= 更新 - 解决方案 =======

对于其他有此问题的人。继Gabuh在下面提出的建议之后;我的完整解决方案是执行以下操作:

func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) 
    if (application.applicationState == UIApplicationState.Background || application.applicationState == UIApplicationState.Inactive)
    
        let navigationController = application.windows[0].rootViewController as UINavigationController;
        navigationController.popToRootViewControllerAnimated(false); // I need to push back to root before performing segue
        let rootViewController = navigationController.visibleViewController;
        rootViewController.performSegueWithIdentifier("showMessageDetail", sender: self);
    

这也允许我调用视图中的函数,例如原始示例中的函数,例如

rootViewController.handleMessageNotificaion(messageID);

rootViewController.messageView.reloadData();

【问题讨论】:

我得到:对于以“let navigationController”开头的行,无法将“myApp.ViewControllerMain”(0x37b18)类型的值转换为“UINavigationController” 我对此不太满意,但这可能表明您的根视图不是导航项?上面的代码假定导航器是根视图。您可能需要添加一个断点以查看您的导航在堆栈中的位置并相应地更改引用。 【参考方案1】:

您正在创建一个新ViewController 的实例。当 ViewController 甚至没有显示时,您正试图在该 ViewController 上调用一个函数,该函数试图执行 segue。我认为那是行不通的……

如果您想从详细视图执行转场,您必须访问当前实例化的视图控制器并从中执行转场。

如果你想知道如何获取正在显示的 UIViewController 的实例,在这篇文章中有几种方法告诉你如何去做:

Get the current view controller from the app delegate

在伪代码中,在您的 appDelegate 中:

1- 获取当前 UIViewController 实例(不是新实例)

2- 从该视图控制器执行 segue(或以模态方式呈现或任何您想要的转换)

【讨论】:

嗨,Gabuh,我尝试了链接解决方案,但它是在 Objective-C 中的 - 幸运的是,在底部附近有一个 swift 等价物。我现在可以在 ViewController 上调用 segue 甚至调用函数。谢谢你。我对“获取当前 ViewController”的唯一问题是:如果您的应用程序中有许多 ViewController 并且必须在它们之间反弹,这不会造成麻烦吗? 谢谢你,加布。我研究了视图控制器的不同入口点。我已经更新了我的问题,以包括您的回答以帮助他人。非常感谢。【参考方案2】:

在 Swift 3 中:

    guard let rvc = self.window?.rootViewController as? VCName else  return 
    rvc.methodInYourVC()

以上假设

    您不想创建一个全新的 VCName 实例,只希望引用它 您知道要引用的 VC 是您的根 VC

【讨论】:

以上是关于从 App Delegate (Swift) 调用 ViewControllers 方法或 Segue的主要内容,如果未能解决你的问题,请参考以下文章

Google Sign In 调用 App Delegate 中的方法后关闭 View Controller (iOS / Swift)

从 App Delegate 调用 ViewController 的方法

从 App Delegate 调用时,PushViewController 不起作用

无法在测试中将 App Delegate 强制转换为 App Delegate

无法在 App Delegate (Swift) 中更新 titleView 图像

App Delegate 中 Core Data 堆栈变量中的 Swift 语法歧义