2

I have created an app that uses storyboard and have successfully created a tableview and detail page which all works.

I would like it so that users swiping the localNotifications can be sent to the correct detail page within the app.

It appears that I can call functions from the ViewController but whenever they refer to themselves to update any details or perform a segue the app crashes.

The code i have in my ViewController is as follows:

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

and this is called from my 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);
  }
}

the println works correctly but performSegue fails (fatal error: unexpectedly found nil while unwrapping an Optional value) and the messageView.reload() fails (same error).

How do I get a notification to fire the app to the correct place upon opening?

This solution 'Get Instance Of ViewController From AppDelegate In Swift' uses much of the same but mine will not allow access to anything with the ViewController.

======= Update - Solution =======

For anyone else with this issue. Following on from what Gabuh had suggested below; the full solution for me was to do the following:

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

this also allows me to make calls on functions in the view such as in the original example e.g.

rootViewController.handleMessageNotificaion(messageID);

or

rootViewController.messageView.reloadData();
Community
  • 1
  • 1
Moss Palmer
  • 1,814
  • 1
  • 15
  • 30
  • I get: Could not cast value of type 'myApp.ViewControllerMain' (0x37b18) to 'UINavigationController' for the line that starts with 'let navigationController' – ProGirlXOXO Aug 12 '15 at 19:34
  • 1
    I'm not great with this but that might suggest that your root view is not a navigation item? The code above assumes that the navigator is the root view. You may need to add a break point to see where in the stack your nav is and alter the reference accordingly. – Moss Palmer Aug 16 '15 at 09:55

2 Answers2

0

You are creating an instance of a new ViewController. And you are trying to call a function on that ViewController, that is trying to perform a segue, when the ViewController is not even displayed. I think that's not going to work...

If you want to perform a segue from your detail view, you have to access to the current instantiated view Controller and perform the segue from it.

If you want to know how to get the instance of the UIViewController that is being displayed, in this post there are several ways that show you how to do it:

Get the current view controller from the app delegate

In pseudo-code, in your appDelegate:

1- get current UIViewController instance (not new one)

2- perfom segue from that view controller (or present modally or whatever transition you want)

Community
  • 1
  • 1
gabuh
  • 1,166
  • 8
  • 15
  • Hi Gabuh, I tried the linked solution but it was in Objective-C - fortunately there was a swift equivalent near the bottom. I can now call the segue and even call functions on the ViewController. Thank You. My only question with "Getting Current ViewController" is: Wouldn't this cause trouble if you had many ViewControllers in your application and had to bounce between them? – Moss Palmer Jan 15 '15 at 17:39
  • Thank you, Gabuh. I worked out the bit about different entry points for the view controllers. I have updated my question to include your answer to help others. Many thanks. – Moss Palmer Jan 16 '15 at 12:30
0

In Swift 3:

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

The above assumes

  1. That you don't want to create a whole new instance of VCName, just want a reference to it
  2. That you know the VC you want to reference is your root VC
Dave G
  • 12,042
  • 7
  • 57
  • 83