26

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?

7 Answers 7

31

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

}
Sign up to request clarification or add additional context in comments.

2 Comments

I know this has been up for a year but i was wondering, if you push to a new view controller you instantiated, does this count as a segue where you can prepareforsegue?
Thank you thank you thank you. Was following some guides that were just grabbing the nav controller from the storyboard and it just wasn't working and this was the trick!
26

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)

4 Comments

Swift 2.0 self.navigationController!.pushViewController(self.storyboard?.instantiateViewControllerWithIdentifier("view2") as! UIViewController, animated: true)
Swift 3.0 self.navigationController!.pushViewController(self.storyboard!.instantiateViewController(withIdentifier: "view2") as UIViewController, animated: true)
self.navigationController is nil. how you push?
@Umitk PushViewController is a part of Navigation API. So without 'UINavigationController' you cont push any. Updated answer to safest way to handle the push
9

APPDELEGATE TO PAGE:

        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let loginPageView = mainStoryboard.instantiateViewControllerWithIdentifier("leadBidderPagerID") as! LeadBidderPage
        var rootViewController = self.window!.rootViewController as! UINavigationController
        rootViewController.pushViewController(loginPageView, animated: true)

PAGE TO PAGE:

        let loginPageView = self.storyboard?.instantiateViewControllerWithIdentifier("scoutPageID") as! ScoutPage
        self.navigationController?.pushViewController(loginPageView, animated: true)

1 Comment

This was the only helpful post I saw in hours. Thanks. Page-to-page was what I was looking for.
2

Updated for swift 3/4. The most voted "one line of code" doesn't work because there's no navigation controller in "self"

let rootViewController = self.window!.rootViewController as! 
UINavigationController
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let profileViewController = mainStoryboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
rootViewController.pushViewController(profileViewController, animated: true)

5 Comments

I dont find window in your solutin
@RishabhDugar Are you in AppDelegate class?
No I am in my Controller File
The solution is for getting the navigation controller from app delegate, not for view controller. In your case, the "one line of code" solution above might be what will work for you.
Signal SIGABRT on line rootViewController
2

Swift 3 & 4 best practices to push viewcontroller from AppDelegate:

if let rootViewController = self.window!.rootViewController as? UINavigationController {
   let storyboard = UIStoryboard(name: "Main", bundle: nil)

   if let viewcontroller = storyboard.instantiateViewController(withIdentifier: "DiscussionBoardSID") as? DiscussionBoardViewController {
      viewcontroller.postID = "13" ///pass data to your viewcontroller
      rootViewController.pushViewController(viewcontroller, animated: true)
   }
}

Comments

0

If you want to present and dismiss with NavigationBar or Dismiss(Animated: true, completion: nil) Set addObserver in didFinishLaunchingWithOptions

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {



NotificationCenter.default.addObserver(self, selector: #selector(devolucionNoPresencial), name: NSNotification.Name(rawValue: "DevolucionNoPresencial"), object: nil)
        return true
}

then in your method

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
//do your code for .active, .inactive .background, etc

 if let userInfo = response.notification.request.content.userInfo as? [String : AnyObject] {
            if UIApplication.shared.applicationState == .active {
//activate the notificationCenter so you can call your @objc method
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "DevolucionNoPresencial"), object: nil)
}

add @objc method

@objc private func devolucionNoPresencial() {


       //change DevolucionVC for VC you want to present

        if let controller = DevolucionVC() as? DevolucionVC {
            if let window = self.window, let rootViewController = window.rootViewController {
                var currentController = rootViewController
                while let presentedController = currentController.presentedViewController {
                    currentController = presentedController
                }
                currentController.present(controller, animated: true, completion: nil)
            }
        }

    }

}

Comments

-1
func pushNewView() {
    if let wind = UIApplication.sharedApplication().delegate?.window {
        if let rootViewController = wind?.rootViewController {
            let viewToPush = YourViewController()
            let nav1 = UINavigationController(rootViewController: viewToPush)
            if let alreadySomeOneThere = rootViewController.presentedViewController {
                alreadySomeOneThere.presentViewController(nav1, animated: true, completion: nil)
            }else {
                rootViewController.presentViewController(nav1, animated: true, completion: nil)
            }
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.