74

I've been trying to redo the work on my app programmatically. (Without the use of storyboards)

I'm almost done, except making the navigation controller manually.

Currently, I only have 1 viewcontroller. And of course the appDelegate

The navigation Controller, will be used throughout all pages in the application.

If anyone could help me out, or send a link to some proper documentation for doing this programmatically it would be greatly appreciated.

EDIT:

I forgot to mention it's in Swift.

maxmitz
  • 258
  • 1
  • 4
  • 17
MLyck
  • 4,959
  • 13
  • 43
  • 74
  • 1
    possible duplicate of [Programatically creating UINavigationController in iOS](http://stackoverflow.com/questions/22981610/programatically-creating-uinavigationcontroller-in-ios) – qwerty_so Mar 02 '15 at 07:25
  • Note that in the vast majority of cases, you can just do it on storyboard ... https://stackoverflow.com/a/22981726/294884 You can then turn off the whacky button bar, and it's "just as good" as doing it programmatically. – Fattie Jan 02 '18 at 19:28
  • 1
    @ThomasKilian How is this a duplication? The other one is objective C but this is Swift?? – user3390652 Sep 28 '18 at 11:13
  • 1
    @user3390652 see the edit history. When the OP asked it was not tagged with Swift. – qwerty_so Sep 28 '18 at 12:10

7 Answers7

115

In AppDelegate.swift

Swift 1, 2:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
   self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
   var nav1 = UINavigationController()
   var mainView = ViewController(nibName: nil, bundle: nil) //ViewController = Name of your controller
   nav1.viewControllers = [mainView]
   self.window!.rootViewController = nav1
   self.window?.makeKeyAndVisible()
}

Swift 4+: and Swift 5+

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
   self.window = UIWindow(frame: UIScreen.main.bounds)
   let nav1 = UINavigationController()
   let mainView = ViewController(nibName: nil, bundle: nil) //ViewController = Name of your controller
   nav1.viewControllers = [mainView]
   self.window!.rootViewController = nav1
   self.window?.makeKeyAndVisible()
}
maxmitz
  • 258
  • 1
  • 4
  • 17
Jogendra.Com
  • 6,394
  • 2
  • 28
  • 35
  • 1
    Nevermind I realized where I went wrong. Changed it back to mainView and did "var mainView = NameOfYourViewController()" And it worked. Thank you so much for the help! – MLyck Mar 02 '15 at 23:53
  • What if i want to add it to a view already has uitabbarcontroller? – TomSawyer Apr 06 '16 at 07:11
  • @TomSawyer , Before adding controller on tabbar , create UINavigationController object using your controller and use that navigation object for add on UITabbarcontroller – Jogendra.Com Apr 06 '16 at 07:15
  • 1
    You can also use the `UINavigationController(rootViewController: _)` initializer instead of assigning an array with one element to the `viewControllers` property. But that is just to save one line of code :) – Kirill Dubovitskiy Apr 26 '17 at 18:04
  • This seems wrong to me (although I know it works, I have used it). the self.window.rootViewController is of type UIViewController, which should in Swift object to being assigned a UINavigationController. – muz the axe May 16 '17 at 11:05
  • This is fine if you want to add the nav controller to the app's main screen, but what about to an arbitrary screen that's presented later? – Oscar Jul 22 '19 at 23:09
  • Why does the mainviewcontroller not fully disappear until the second view has loaded. For a a fraction of a second you can see both views on screen ? Also how does one add swipe to go back ? – VynlJunkie Aug 09 '19 at 10:36
23

Value of type 'AppDelegate' has no member 'window'

For those building newer projects with SceneDelegate.swift, you can use the 'var window: UIWindow?' in SceneDelegate instead of the removed 'var window' in AppDelegate

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }

    window?.windowScene = windowScene
    window?.makeKeyAndVisible()

    let viewController = ViewController()
    let navViewController = UINavigationController(rootViewController: viewController)
    window?.rootViewController = navViewController
}
candyline
  • 788
  • 8
  • 17
  • Thanks, I suppose to set naviBar in single view controller, and unable to figure out it constraint. Now I know that is wrong. It should be set in AppDelegate or SceneDelegate as global use. – Zhou Haibo Nov 04 '20 at 17:35
17

I would recommend starting your AppDelegate with this skeleton:

1) use let wherever you can!

2) UINavigationController has the rootViewController property.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    let viewController = ViewController(nibName: nil, bundle: nil) //ViewController = Name of your controller
    let navigationController = UINavigationController(rootViewController: viewController)

    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    self.window?.rootViewController = navigationController
    self.window?.makeKeyAndVisible()

    return true
}
Barrett
  • 323
  • 5
  • 11
telenaut
  • 380
  • 2
  • 14
9

Here is another take in the SceneDelegate class:

var window: UIWindow?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

    if let windowScene = scene as? UIWindowScene {

        let window = UIWindow(windowScene: windowScene)    
        let navController = UINavigationController()
        let viewController = ViewController()

        navController.viewControllers = [viewController]            
        window.rootViewController = navController
        self.window = window
        window.makeKeyAndVisible()
    }
}
Linus
  • 423
  • 5
  • 12
  • how to make it work with tabbarcontrolle so it shows the title? – Lukasz D Oct 05 '21 at 19:13
  • I'm not entirely sure that I know what your asking for. You would just add the UITabBarController as the rootViewController like this -> window.rootViewController = MyTabBarController() – Linus Oct 07 '21 at 21:38
3

Try this one . It will guide you how to use navigation controller.

Programatically creating UINavigationController in iOS

AppDelegate.h

    #import <UIKit/UIKit.h>
    #import "LoginViewController.h"

    @interface AppDelegate : UIResponder <UIApplicationDelegate>

    @property (strong, nonatomic) UIWindow *window;
    @property (strong,nonatomic) UINavigationController *navigationController;
    @property (strong,nonatomic) LoginViewController *loginVC;

    @end

AppDelegate.m

    #import "AppDelegate.h"
    #import "LoginViewController.h"

    @implementation AppDelegate

  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.

   self.loginVC = [[LoginViewController alloc]initWithNibName:nil bundle:nil];
   self.loginVC.title = @"Login Page";

   self.navigationController = [[UINavigationController alloc]initWithRootViewController:self.loginVC];

   self.window.rootViewController = self.navigationController;
   [self.window makeKeyAndVisible];
  }

Then when you want to push the other view controller , simple use following code to move to another view controller.

- (IBAction)pushMyProfileView:(id)sender
{
    self.myProfileVC = [[MyProfileViewController alloc]initWithNibName:nil bundle:nil];
    [appDelegate.navigationController pushViewController:self.myProfileVC animated:YES];
}
Community
  • 1
  • 1
Hardik Shekhat
  • 1,680
  • 12
  • 21
  • Hey, thank you so much for the reply!. I know this is completely my own fault, I only added it as a tag and forgot to mention it. But I'm coding it in swift. Unfortunately I have no idea how to translate that code to swift. – MLyck Mar 02 '15 at 22:50
  • 1
    The answer should have been in swift – Umair Afzal Jun 03 '16 at 05:34
  • @UmairAfzal okay I will be post updated code for swift very soon if you have needed it. – Hardik Shekhat Jun 03 '16 at 06:14
  • @HardikShekhat actually I do need please reffer to my question. http://stackoverflow.com/questions/37606778/how-to-navigate-all-views-of-application-using-navigation-controller-in-ios-usin/37606892#37606892 – Umair Afzal Jun 03 '16 at 06:18
  • 1
    @UmairAfzal I will post answer there for swift. – Hardik Shekhat Jun 03 '16 at 06:20
0

It is probably overkill, but I find myself doing this often enough that I just extended UIViewController and created an embedInNavigationController method. So now I can just call viewController.embedInNavigationController.

extension UIViewController {

func embedInNavigationController() -> UINavigationController {
    return UINavigationController(rootViewController: self)
   }
}
-3
 self.window = UIWindow(frame: UIScreen.main.bounds) 
 let storyboard = UIStoryboard(name: "Main", bundle: nil) 
 let storyboard_Secondary = UIStoryboard(name: "Secondary", bundle: nil) 
 var initialViewController = UIViewController() 

 let aUser = CommonMethods.loadCustomObject("\(Constants.kUserProfile)") as? User  
 if aUser?.respCode == 1 { 
    initialViewController = storyboard_Secondary.instantiateViewController(withIdentifier: "MainTabVC")
    UIApplication.shared.statusBarStyle = .lightContent
    let navigationController = UINavigationController(rootViewController: initialViewController)
    navigationController.isNavigationBarHidden = true
    self.window!.rootViewController = navigationController
    self.window!.makeKeyAndVisible() 
}
lukkea
  • 3,606
  • 2
  • 37
  • 51
Nikunj Patel
  • 304
  • 2
  • 7
  • 2
    This answer is not general, and relies on a class that is not part of the language. This answer also does not show the import of that class, nor does it say anything about where the class came from or how to get it. It is entirely possible to rewrite this without anything in CommonMethods, resulting in fewer lines of code, and a more general answer. There is additional styling code in here that is not required for the NavigationController to work properly. – miles_b Jan 23 '19 at 21:41