setRootViewController: doesn't work as expected after setViewControllers: have been called - ios

I created a view controller programmatically and set it as a root controller. All worked perfect as it was expected:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CustomViewController *vc = [[CustomViewController alloc] init];
[[self window] setRootViewController:vc];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
Then I added an UITabBarViewController, set its 'viewControllers' property to point to (an array to) the main viewController 'vc'.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CustomViewController *vc = [[CustomViewController alloc] init];
UITabBarController *tbc = [[UITabBarController alloc] init];
NSArray *controllers = #[vc];
[tbc setViewControllers:controllers];
[[self window] setRootViewController:vc];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
and the view stoped to show at the screen upon launch, also there is warning about the root view controller wasn't set. After adding the string below the view of 'vc' controller is finally loaded, but there is a blank line at the bottom of the screen, as if the UIBarController modified [[UIMainScreen bounds].
[[self window] addSubview:vc.view];
I'm new to iOS development, and I'm a bit confused. It seems I don't understand some very fundamental things about the view controllers hierarchy, but after reading the "View Controller Programming Guide" by Apple, I still don't understand where am I wrong.
The setRootViewController: method should auto assign the _view of argument view controller as default view of the window, but it doesn't happen if the named view controller was already previously pointed by viewControllers property of UITabBarViewController. Though I checked the debugger and found that 'vc' object isn't changed after setViewControllers: method is called.
Could you please explain me what is going on or point me to a documentation I should read?
UPDATE: I'm not going to insert the 'vc' controller into the 'tbc' controller. What I'd like is to display the 'vc' view fullscreen, as it would normally displayed without the code about 'tbc'.
From my point of view, adding another view (tbc in my case) should NOT affect this behaviour.
Of course, that's pretty useless from practical point of view, but I'd like to know what's going on under the hood.

You should set tbc as rootViewController.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CustomViewController *vc = [[CustomViewController alloc] init];
UITabBarController *tbc = [[UITabBarController alloc] init];
NSArray *controllers = #[vc];
[tbc setViewControllers:controllers];
[[self window] setRootViewController:tbc];
[[self window] addSubview:tbc.view];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;

When you add vc to the tab bar controller, it becomes a child of that controller. The root view controller of the window can't be a child, which is why you get that error. If you want vc to be full screen, then don't put it in the tab bar controller, and then at some point, you switch the window's root view controller to be the tab bar controller (if that's what you want).
You haven't said what you want to use vc for. A better way, depending on its use, might be to present it modally (so it takes the whole screen) from whichever controller is in the first tab of your tab bar controller. Do this from viewDidAppear, and it will be the firsts thing the user sees when the app starts up.

Related

ViewController loaded in AppDelegate BUT shifted down

Inside AppDelegate.m file I have:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.MainVC = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.HamMenuVC = [[HamMenuViewController alloc] initWithNibName:#"HamMenuViewController" bundle:nil];
self.RevealVC = [[SWRevealViewController alloc]initWithRearViewController:self.HamMenuVC frontViewController:self.MainVC];
self.navC = [[UINavigationController alloc]initWithRootViewController:self.RevealVC];
self.window.rootViewController = self.navC;
[self.window makeKeyAndVisible];
Which is supposed to load my Main VC and then the hamburger menu VC (or slider? in iOS talk), and when I start the app I get the loaded VCs BUT the entire view seems to be shifted down roughly 30 pixels and there's this white space above.
As you can see below, this is the top of my screen and the black is where the MainVC starts:
the top of the screen
I've checked the 'self.view.frame.origin.y' inside the MainVC and it says 0.0 AND I've checked the '[[UIScreen mainScreen] bounds].size.height' and it's giving me the correct height for the device I'm running it on AND I checked the '[[UIScreen mainScreen] bounds].origin.y' and it says 0.0.
Does anyone have a clue why all the data is saying it's in the right place but the fact is it's in the wrong place on my physical device AND on any simulator I choose?
It looks like that's the UINavigationBar on top of the screen. In your code, you're setting your rootViewController with a UINavigationController.
self.navC = [[UINavigationController alloc]initWithRootViewController:self.RevealVC];
self.window.rootViewController = self.navC;
If you need to hide the navigation bar, call this method in your RevealVC's viewDidLoad method:
[self.navigationController setNavigationBarHidden:YES animated:YES];
Also, quick tip, try to name your properties starting with lowercase letters.

iOS navigation controller without navigation bar

This is how I launched by main controller in my iOS app.
UIViewController *rootController = [[RootViewController alloc] init];
navigationController = [[UINavigationController alloc] initWithRootViewController:rootController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:navigationController];
[self.window makeKeyAndVisible];
return YES;
With this I am getting a blank bar at the top.
I want to use a navigation controller to control the flow of screens that users are able to reach by pressing back but I don't want a navigation bar. How can I change my code to get what I want?
You can use this code right after you declare navigationController = ... in the code sample you provided:
[navigationController setNavigationBarHidden:true];
And then whenever you need to go "back," your app would run this code from within the current view controller:
[self.navigationController popViewControllerAnimated:true];

Navigation Controller with TabBarController in App

I am trying to make a tableview with two views, the tableview controller and the otherView controller. The tableview needs a navigation controller to get to a third view when a cell is clicked. I tried using the code below in my AppDelegate.m but it just creates the tableview with the navigation controller. Any suggestions on how I should edit this to get the tabview working as well? Thanks!
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
AJBTableViewController *masterViewController = [[AJBTableViewController alloc] initWithNibName:nil bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
_mainTabBar.viewControllers = [NSArray arrayWithObjects:_navigationController, otherViewController, nil];
[_window addSubview:_mainTabBar.view];
return YES;
}
The tab bar controller should be the root view controller of the app, not the navigation controller of the first tab bar item.
_mainTabBar.viewControllers = [NSArray arrayWithObjects:_navigationController, otherViewController, nil];
[_window addSubview:_mainTabBar.view];
Instead this code, you try below code:
UITabBarController *tbC = [[UITabBarController alloc]init];
tbC.viewControllers = [NSArray arrayWithObjects:_navigationController,otherViewController, nil];
self.window.rootViewController = tbC;
and delete
self.window.rootViewController = self.navigationController;
Sorry for the stupid error, I never allocated an instance of the tabbar controller, Mundi is right, making the rootviewcontroller the tabbarcontroller is the way to go.

Objective-C: how to set keywindow to different viewcontroller in Xcode?

I am using storyboards and this code but nothing is appearing in my current viewConntroller but is in my first viewConntroller. Can anybody eli me set the keywindow to the current view i am on?
Here is the code i am using to show my UINavigationBar
[[[UIApplication sharedApplication] keyWindow] addSubview:bar];
Thanks in advance
you dont set the Viewcontroller to a Window
you need to do something like this:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
this is how you add a uinavigationcontroller:
Add a UINavigationBar to a UITableViewController without a UINavigationController
if you want to present a new view controller
you simply use presentModalViewcontroller:
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationcontroller vc animated:YES];
// I have written it all down just check the case and use it

Tabbed application won't show Login view

I have a tab bar application in Xcode 4.3 and I'm trying to insert a login screen before the tabbar is shown. The app works OK if presentModalViewController has animated:YESbut if it is without animation the view is not showing.
#synthesize window = _window;
#synthesize tabBarController = _tabBarController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
LogInViewController *logViewController = [[LogInViewController alloc] initWithNibName:#"LogInViewController" bundle:nil];
[self.window addSubview:_tabBarController.view];
[self.tabBarController presentModalViewController:logViewController animated:YES];
//This wont work
//[self.tabBarController presentModalViewController:logViewController animated:NO];
[self.window makeKeyAndVisible];
return YES;
}
-(void)loginDone{
NSLog(#"back to the app delegate");
[self.tabBarController dismissModalViewControllerAnimated:YES];
}
Is this the right way to do it?
Why wont the code work with animated:NO ?
I also get this on output Unbalanced calls to begin/end appearance transitions for <UITabBarController: 0x689d350>.
First of all, move [self.window makeKeyAndVisible]; before your view controller setup.
Additionally, you should be presenting the modal view controller within the viewWillAppear: method of the view controller that will be visible first, to make sure your apps view hierarchy has been fully initialized before presenting your login screen.
Don't do this:
[self.window addSubview:_tabBarController.view];
Do this:
self.window.rootViewController = _tabBarController;
This will put the tabBarController on the screen. But that's not exactly what you want... My advise is:
1) Start by putting the logViewController has the rootViewController as I showed you above.
2) Once you got what you want (login is successful) just tell the AppDelegate to switch the rootViewController. This can be done in with delegation or notifications.
Also, as Toastor indirectly pointed out, you should start the presentViewController from the UIViewController who actually initiates it (and not from the AppDelegate).

Resources