navigation controller pushViewController not working - ios

I'm creating an application that has 2 main view controllers at the moment. The app loads into the initial viewController, and clicking a button inside should bring up the second viewController. Here's what I have:
AppDelegate.h
#import <UIKit/UIKit.h>
#import "ViewController1.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController1 *mainViewCtr;
#property (strong, nonatomic) UINavigationController *navigationController;
#end
AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
_mainViewCtr = [[ViewController1 alloc] initWithNibName:#"mainViewCtr" bundle:nil];
_navigationController = [[UINavigationController alloc] initWithRootViewController:_mainViewCtr];
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.rootViewController = _navigationController;
_navigationController.delegate = self;
_navigationController.navigationBarHidden = YES;
[_window addSubview:_navigationController.view];
[self.window makeKeyAndVisible];
}
and my button method inside viewcontroller1:
- (IBAction)SessionNickNameSubmit:(id)sender {
ViewController2 *secondViewCtrl = [[ViewController2 alloc] initWithNibName:#"secondViewCtrl" bundle:nil];
[self.navigationController pushViewController:secondViewCtrl animated:YES];
}
but when I click the button the view doesn't change. I tried debugging and the code is hit, but nothing happens.
am I missing a setting somewhere?
UPDATE
I've updated all viewController variable names:
instead of ViewController1/2 I'm using mainViewCtrl and secondViewCtrl
but still no use :(

You made a typo:
it's
_window.rootViewController = _navigationController;
not
_window.rootViewController = _joinViewController;
And NeverHopeless's suggestion is also spot on. It's probably the typo AND the fact that you add your second viewcontroller as ViewController2 and not using a proper variable name.
Another suggestion is making a storyboard (if you are not using one) and adding a segue for the transition. Simply assign the segue processing to the button. Like this:
-(IBAction)SessionNicknameSubmit:(id)sender
{
[self performSegueWithIdentifier:#"identifier" sender:self ];
}
Here is a nice description of how it works and how to use it plus some useful pointers!

Obj-C is a case sensitive language, class name and instance name should not be the same like ViewController2. Try like this:
- (IBAction)SessionNickNameSubmit:(id)sender {
ViewController2 *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[self.navigationController pushViewController:viewController2 animated:YES];
}

The reason is that you have set the window's rootViewController to ViewController1.
You need to set you navigation controller to the window's rootViewController.
So that when you try to access the self.navigationController on the press of the button, it will access the navigation controller in which the self resides i.e. your window's rootViewController now.
Then it will push the next view controller properly.

After looking at almost every tutorial and every stack overflow answer, I finally found a solution that worked. I had to make an instance of the storyboard in the app delegate and use that to create my first view controller instance.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.joinViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController1"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:joinViewController];
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
navigationController.navigationBarHidden = YES;
_window.rootViewController = navigationController;
[_window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
I think the problem was that when I was creating an instance of ViewController, it was creating a new instance and binding the navigation controller to it (independent of the view controller that was showing up in the simulator). So when I was using the push method it wasn't recognizing self.NavigationController (that's why NSLog(self.NavigationController == nil) was logging 1

Related

iOS How can I use pushviewcontroller with NavigationController(Objective - c)

I want to change view by clicking button with NavigationController
So I added a button to Main.storyboard and write some codes like
#property (weak, nonatomic) IBOutlet UIButton *button;
in my ViewController.m (Created automatically when I made my project)
And I added method
- (IBAction)buttonClicked:(id)sender {
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
}
(I made SecondViewController.m, SecondViewController.h, SecondViewController.xib)
After this, I started the application and clicked the button but the screen didn't change.
Actually, when I added log like
NSLog(#"%#", self.navigationController);
null was printed.
I think I need to add some code about NavigationController to AppDelegate.m but I don't know what to do. Please help me.
Try This,
in Appdelegate.m
`- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController"
bundle:nil];
UINavigationController *navigation = [[UINavigationController alloc]initWithRootViewController:self.viewController];
self.window.rootViewController = navigation;
[self.window makeKeyAndVisible];
return YES;
}`
You need to embed Navigation Controller through code or Storyboard.
First select your initial viewcontroller in storyboard and embed it in NavigationController.
Then give a storyboard identifier to the second viewcontroller.
Then lastly instantiate Second ViewController from storyboard and push it.
- (IBAction)buttonClicked:(id)sender {
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:entryController animated:YES];
}

How do I start another view controller with no storyboard?

I'm not using a storyboard or anything. I'm just creating the cocoa classes and linking them up individually. I can get to load up the default View Controller which is SplashViewController but i can't get past there.
I have experience in php, android programming and python, but i'm totally clueless on how Obj-C and how the iOS framework works :(
SplashViewController.m
-(void)initializeInterface
{
//Initialize start button
[self.startButton addTarget:self action:#selector(startActivity) forControlEvents:UIControlEventTouchDown];
//Initialize fading backgrounds
[self animateImages];
}
-(void)startActivity
{
PhoneViewController *phoneView = [[PhoneViewController alloc] initWithNibName:#"PhoneViewController" bundle:nil];
[self.navigationController pushViewController:phoneView animated:YES];
}
SplashViewController.h
#import <UIKit/UIKit.h>
#import "PhoneViewController.m"
#class PhoneViewController;
#interface SplashViewController : UIViewController
#property (strong, nonatomic) PhoneViewController * phoneViewController;
#property UIImage *splashbg1;
#property UIImage *splashbg2;
#property (nonatomic, retain) IBOutlet UIImageView *splashbg;
#property (nonatomic, retain) IBOutlet UIButton *startButton;
-(void)initializeInterface;
-(void)animateImages;
-(void)startActivity;
#end
EDIT
classAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
//Move from delegate view controller to root view controller
self.window.rootViewController=[SplashViewController new];
[self.window makeKeyAndVisible];
return YES;
}
Wrap your splash view controller in a navigation controller.
Otherwise, the navigationController property of your splash view controller is nil and pushViewController has no effect.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: splashViewController];
To move from one UIViewController to other UIViewController, you can try the following things
If SecondViewController *secondViewController is the UIViewController you want to move in to, then your can do the following:
[self presentViewController: secondViewController animated:YES completion:nil];
This is when you UIViewController is not embedded inside a UINavigationController.
It is possible to create your view controllers entirely in code without using Storyboards or XIB files, but it's not recommended. It's like trying to write a complex user application in assembler. The state of the art has evolved since the days when that was necessary. There are better tools. Use them.
Creating everything yourself is both quite complex and not very well documented. You are setting yourself up for a very frustrating, error-prone process. I've been doing iOS development pretty much full time since 2009, and I would not attempt this.
That being said, if you are a masochist, you would create your view controller using initWithNibName:bundle:, passing in nil for both parameters, and then implement the loadView method. In loadView you're create your view hierarchy and install it.
If you are new to iOS/Objective-C, DO NOT DO THIS. It is like trying to write a kernel device driver in machine code as your first foray into UNIX.
Change you AppDelegate method as below -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
UINavigationController *navcon = [[UINavigationController alloc]initWithRootViewController:[SplashViewController new]];
//Move from delegate view controller to root view controller
self.window.rootViewController=navcon;
[self.window makeKeyAndVisible];
return YES;
}
Problem in your code, you have not taken any navigationController, that enables you push or pop UIViewController. Doing above you can use your method -(void)startActivity to Start a new ViewController.

Changing root view controller in the background

I have the following view controllers stack.
First, my app will show an app tour page. (Say TourViewController - super class is UIViewController). Added this controller in AppDelegate as rootviewcontroller.
self.window.rootViewController = tourViewController;
Then from the tour page, if the user taps on "Signin" button, I'm presenting the second view controller (Say LoginViewController - super class is UIViewController).
UINavigationController *loginNavigationController = [[UINavigationController alloc] initWithRootViewController:self.loginViewController];
[self presentViewController:loginNavigationController animated:YES completion:nil];
After a successful login, I need to resign the second view controller (LoginViewController) and want to show a tab bar based view for further needs.
I tried this code inside the login success method.
[self dismissViewControllerAnimated:YES completion:^{
TabBarViewController *tabController = [[TabBarViewController alloc] init];
[self presentViewController:tabController animated:NO completion:nil];
AppDelegate *applicationDelegate = [[UIApplication sharedApplication] delegate];
applicationDelegate.window.rootViewController = tabController;
}];
Problems:
When I'm in the LoginViewController, I have two view controllers in my stack. So even I resign the LoginViewController, the another one (TourViewController) remains in the screen.
If I tried the above code, tab bat controller was successfully added as root view controller. But, when the LoginViewController resigns, the background was filled by TourViewController
What I need is, When I resign the LoginViewController, the background view should be tab bar controller instead of TourViewController.
Help needed!!
u can change the root view controller in AppDelegate not in the success method of the loginNavigationController better u can do this way
in AppDelegate.h
#import <UIKit/UIKit.h>
#import "TabControllerViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
- (void)showTabController; //add this method call from on success method of log in completion
#end
in AppDelegate.m
- (void)showTabController;
{
TabControllerViewController *tabController = [[TabControllerViewController alloc] initWithNibName:#"TabControllerViewController" bundle:nil];
self.window.rootViewController = tabController;
[self.window makeKeyAndVisible];
}
and in loginNavigationController.m
[self dismissViewControllerAnimated:YES completion:^{
//TabBarViewController *tabController = [[TabBarViewController alloc] init];
// [self presentViewController:tabController animated:NO completion:nil]; //no nee to present
AppDelegate *applicationDelegate = [[UIApplication sharedApplication] delegate];
[applicationDelegate showTabController]; //there is no need to create a tab bar in loginview controller, create it in root view controller
//applicationDelegate.window.rootViewController = tabController;
}];
NOTE: above is not tested just try it once
Edit 1
one way u can do it but with different animation,
form this answer u can change to second window by doing some animation for example
in in AppDelegate.h
#import <UIKit/UIKit.h>
#import "TabViewController.h"
#import "LoginViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window; //holds initial window, holds tour and login controller
#property (strong, nonatomic) UIWindow *tabWindow; //holds only tab controller
//..other code below is my test
#property (strong, nonatomic) TabViewController *tabViewController;
#property (strong, nonatomic) LoginViewController *loginController;
- (void)showTabController;
#end
in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_tabWindow = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
_window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
// Override point for customization after application launch.
_loginController = [[LoginViewController alloc]initWithNibName:#"LoginViewController" bundle:nil];
_tabViewController = [[TabViewController alloc] initWithNibName:#"TabViewController" bundle:nil];
self.window.rootViewController = _loginController; //for test for your case it contains tour view controller
[self.window makeKeyAndVisible];
return YES;
}
- (void)showTabController;
{
[UIView transitionWithView:self.window duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
self.window.rootViewController = _tabViewController;
} completion:^(BOOL finished) {
// [_tabWindow makeKeyAndVisible];
}];
}
Do one thing,
Create UINavigationController in AppDelegate.h so you can access it anywhere.
Logic
Whenever you need to change navigation controller you must have to put your Controller to Navigation stack.
So first of all you have to create ViewController/ Tabbarcontroller object and assign it to navigationController and then show the navigationController.
AppDelegate* myDelegate = (((AppDelegate*) [UIApplication sharedApplication].delegate));
InitialViewController *initialVC = [self.storyboard instantiateViewControllerWithIdentifier:#“InitialVC"];
myDelegate.navController = [[UINavigationController alloc] initWithRootViewController:initialVC];
myDelegate.window.rootViewController = myDelegate.navController;
[myDelegate.window makeKeyAndVisible];

Not understanding how the NavigationController and UIViewControllers are working in iOS

I have a project which I don't really understand the views and navigation behind. I start out in the AppDelegate (MAAppDelegate), where I define properties:
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UIViewController *detailViewController;
Then in the MAAppDelegate.m, I create a navigationController, and
#implementation MAAppDelegate
#synthesize detailViewController;
#synthesize window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Init the navController for the Master Detail View of the grade cells
UINavigationController *navController = [[UINavigationController alloc] init];
detailViewController = [[UIViewController alloc] init];
UIViewController *viewController = [[MAController alloc] init];
navController = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}
So at this point, I think I have a working naviationController, I've setup an instance of a custom UIViewController (custom class MAController) and I've set it up as the rootViewController.
Then, in my MAController class, the class where I do all of my UI stuff (the entire UI is done programmatically, no nibs or storyboards). Here is a bit of the viewDidLoad of MAController:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.navigationController setNavigationBarHidden:YES]; // I commented this line out and realized it does nothing
I go on (in viewDidLoad) to add a bunch of subviews to self.view, like this
[self.view addSubview:self.backgroundImageView];
Earlier, I created a viewController in the AppDelegate class and it was called view, so I assumed it was refereeing to that but now since I've changed it (in AppDelegate) to viewController, I guess I was thinking wrong?
And then finally, I create a UIView in 'viewDidLoad`:
UIView *header = [[UIView alloc] initWithFrame:headerFrame];
header.backgroundColor = [UIColor clearColor];
self.tableView.tableHeaderView = header;
and start adding a bunch of subviews to this new UIView I created header.
So, in short, I have no idea what is happening. Later, when I tried telling (from a method inside MAController) self.navigationController (which I assumed to be navigationController in charge of everything in my project - created at the beginning in the AppDelegate) to pushViewController a new viewController that I was going to use as a detailView for a table, it got weird.
So I'm just trying to understand what has control, and what the rootViewController is, and just what is happening.
The main window root is set to a view controller and not the navigation controller
Change:
self.window.rootViewController = viewController;
to:
self.window.rootViewController = navController;
EDIT:
You can access the navigationController from anywhere by asking your appDelegate. It is normally not considered a good practice:
MAAppDelegate *delegate = (MAAppDelegate *)[[UIApplication sharedApplication] delegate];
UINavigationController *nav = delegate.navigationController;
Don't forget to:
#import "MAAppDelegate.h"
First, take a little time and read through how navigation controllers work. The documentation is really helpful:
https://developer.apple.com/library/ios/documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
Second, your problem is that your window's root view controller is not the navigation controller you created. Rather it is an instance of MAController. This is what you're doing:
UIViewController *viewController = [[MAController alloc] init];
// some other code ...
self.window.rootViewController = viewController;
I think you meant to add MAController as the root view controller of the navigation controller and make the navigation controller your window's root. If so, you'll want to set your view controllers up like this:
UIViewController *viewController = [[MAController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = navController;
Another potential problem is that you don't seem to be doing anything with your detailViewController. Maybe that's confusing you too.

PushViewController to current navigation controller from another class

I am creating a class object from my UIViewController and trying to push a controller from it, and it won't work.
I have been doing research but found nothing, any idea?
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.newClass = [[MyNewClass alloc] init];
self.newClass.view = self.view;
self.newClass.navigationController = self.navigationController;
[self.newClass connect];
}
...
#end
MyNewClass.h
#interface MyNewClass : NSObject<UINavigationControllerDelegate>
#property(nonatomic, retain) UIView *view;
#property(nonatomic, retain) UINavigationController *navigationController;
-(void) connect;
#end
MyNewClass.m
-(void)connect
{
OtherViewController * otherVC =
[[OtherViewController alloc] init];
self.navigationController pushViewController:otherVC animated:YES];
}
...
add folloeing code into appdelegate's didFinishLaunchingWithOptions method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self copyDatabaseIfNeeded];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.window makeKeyAndVisible];
return YES;
}
and then remove all other UINavigationController declaration and allocation. Like MyNewClass's NavigationVontroller. Because here you declare and allocate navigationcontroller in appdelegate so you can use it in whole app.
When viewDidLoad is called, the view has just been loaded but the view controller hasn't necessarily been added to a navigation controller yet. So using viewDidLoad as your trigger is not useful.
A better approach is to explicitly pass the navigation controller to the view controller when it's created. Or to implement didMoveToParentViewController: and do your configuration there.
You are pushing a viewController from a controller, which is not a part of navigationController, so first make it part of navigationController, then try

Resources