Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - pushViewController from appDelegate, rootViewController.navigationController is nil

Having a problem following a few guides, specifically http://blog.originate.com/blog/2014/04/22/deeplinking-in-ios/

I'm setting the url scheme and it's working well to launch the app from another app, but passing in the host or url are not working as it seems it should. I'm using storyboards and interface builder for all the view layouts.

The guide shows this openURL in appDelegate:

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{     if([[url host] isEqualToString:@"page"]){         if([[url path] isEqualToString:@"/page1"]){             [self.mainController pushViewController:[[Page1ViewController alloc] init] animated:YES];         }     return YES;     } } 

Here is my version simplified and in swift from a few other sources, ie Get Instance Of ViewController From AppDelegate In Swift I'm skipping the conditional for the url host at the moment to remove potential other variables in the problem.

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String, annotation: AnyObject?) -> Bool {     var rootViewController = self.window!.rootViewController     let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)     var profileViewController = mainStoryboard.instantiateViewControllerWithIdentifier("profile") as ProfileViewController      rootViewController.navigationController.popToViewController(profileViewController, animated: true)      return true  } 

The swift version causes a crash: fatal error: unexpectedly found nil while unwrapping an Optional value

It seems that rootViewController doesn't have a navigationController yet?

like image 535
tehfailsafe Avatar asked Aug 12 '14 04:08

tehfailsafe


People also ask

How to get navigation controller root view controller?

The root view controller is simply the view controller that sits at the bottom of the navigation stack. You can access the navigation controller's array of view controllers through its viewControllers property. To access the root view controller, we ask for the first item of the array of view controllers.

How to get current view controller in navigation controller?

You can check whether a controller's view is on screen by looking at self. view. window -- that will be nil if the view is not currently in the window's hierarchy.


2 Answers

It seems that rootViewController actually is of type UINavigationController in my case, so casting it on declaration allowed me to call pushToViewController directly on it.

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String, annotation: AnyObject?) -> Bool {     let rootViewController = self.window!.rootViewController as! UINavigationController     let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)     let profileViewController = mainStoryboard.instantiateViewController(withIdentifier: "InstructionVC") as! InstructionVC     rootViewController.pushViewController(profileViewController, animated: true)     return true  } 
like image 63
tehfailsafe Avatar answered Oct 14 '22 23:10

tehfailsafe


SWIFT 4: Safe way to push with the use of conditional binding and Chaining

if let navController = self.navigationController, let viewController = self.storyboard?.instantiateViewController(withIdentifier: "indentfier") as? CustomViewController{     navController.pushViewController(viewController, animated: true) } 

In One line of code :

Swift 3:

self.navigationController!.pushViewController(self.storyboar‌​d!.instantiateViewCo‌​ntroller(withIdentif‌​ier: "view2") as UIViewController, animated: true) 

self.navigationController!.pushViewController(self.storyboard!.instantiateViewControllerWithIdentifier("view2") as UIViewController, animated: true) 
like image 33
Kumar KL Avatar answered Oct 15 '22 00:10

Kumar KL