I am developing an iOS app and using storyboards. In my storyboard, I had set a view controller as the initial view controller. Everything working fine.
Now I have to write some login in app delegate to decide which view controller to show at the beginning because this depends on how far the user is in the login process.
So, I removed the initial view controller mark from my storyboard and removed the storyboard setting from my plist file.
Now, in the app delegate I have this code -
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
UIViewController *initialViewController = [storyboard instantiateViewControllerWithIdentifier:[XYZUtils getStartScreenViewController]];
XYZStartScreenViewController *startScreenViewController = (XYZStartScreenViewController *)initialViewController;
[self.window addSubview:startScreenViewController.view];
[self.window setRootViewController:startScreenViewController];
[self.window setBackgroundColor:[UIColor whiteColor]];
[self.window makeKeyAndVisible];
This does not display the view controller - I am just getting a black screen and no error messages. On using breakpoints to walk through the above code, there is no error. The view controller is being instantiated but it is not getting displayed.
Am I missing something here?
Read this post..
It is better you make an empty view controller and mark that as initial view controller
And do all login process in that view controller's viewDidLoad method.
Linking a new viewcontroller to Storyboard?
For some reason, when you deselect the initial view controller setting in the storyboard, then your app will not get a UIWindow setup in didFinishLaunching.
So, what you should so is instantiate your own window there; just add this to the beginning of your application didFinishLaunchingWithOptions method:
UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
I think this solution is perfectly fine, but a "cleaner" one since you are using the storyboard, is having some sort of "LoginManagerViewController" as your initial view controller with the responsibility of handling where to do next based on how far the user is in the login process.
Related
I have a main view controller using a navigation controller and i was making my application over that. Now i want to add a welcome view controller for my app and make it show first instead of my main view controller. Is there any way to do it.
What I did was adding a view controller to my storyboard and added two classes of the same name then i made it my root view controller and unchecked the root view controller from the main view but it is not showing on the window. Please help me, that how can i make my welcome view to appear before the main view controller. Thanks
Inside Interface Builder, under the attributes section (looks like a small slider) about a quarter of the way down the list of settings, there is a section labeled "View Controller." The second item in that section is a checkbox "Is Initial View Controller," check that box and you should see the starting arrow of the story board move to the specified view controller and the app should launch to that page.
Hope this Helps.
You could do this programmatically by setting the app window's rootViewController. From the app delegate's application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIScreen *mainScreen = [UIScreen mainScreen];
self.window = [[KTAppWindow alloc] initWithFrame:mainScreen.bounds];
[window makeKeyAndVisible];
window.rootViewController = [[WelcomeViewController alloc] init];
return YES;
}
Then you just need to set up your trigger to switch from the Welcome view to the main view. This could be scheduling an NSTimer, for example. Whatever the trigger is, once it occurs just change the window's rootViewController instance to your MainViewController.
I hope this helps.
It calls "Splash Screen" you just need to add a new ViewController in your Storyboard or if you don't have a Navigation Controller add.
In the Splash class, in the viewDidLoad method you need to put this:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
HomeViewController *vc = [sb instantiateViewControllerWithIdentifier:#"Home"];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:vc];
[self performSegueWithIdentifier:#"Home" sender:self];
here you can add conditions if you needed
There are two views in my application.
After launching the app I switch the view with button like this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:[NSBundle mainBundle]];
UIViewController *view = [storyboard instantiateViewControllerWithIdentifier:#"view_a"];
[self presentViewController:view_a animated:NO completion:nil];
But whenever i switch the view the code above initialize the view.
I want to maintain previous status of the view.
How can I solve this problem?
instantiateViewControllerWithIdentifier: always returns a new instance of an UIViewController.
You need to keep a reference to a previous one if you don't want to create it over and over.
On an iPad this will present the second view modally, as dictated by the views modalTransitionStyle. So there you could get back to the original by calling dismissViewControllerAnimated:completion: on the new ViewController.
On the iPhone you can use a UINavigationController in your storyboard to push and then pop the secondViewController.
As long as you are using the storyboard, you can set up the transition there and the perform it using - performSegueWithIdentifier:sender: from your button. Or for that matter you can connect the segue directly to your button in which case the transition will be performed without additional code.
In my app I have an ECSlidingViewController declared as initial root controller via Storyboard. In my AppDelegate's didFinishLaunchingWithOptions method, I instantiate it as above:
self.slidingController = [[UIStoryboard storyboardWithName:#"AppStoryboard" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"ECSlidingViewController"];
What I want is to be able to show a global modal view controller (eg. when a push notification arrives while the app is active) without knowing which controller is currently top in the sliding controller.
What I do is (in my AppDelegate):
[self.slidingController.topViewController presentModalViewController:controller animated:YES];
but it doesn't seem to work.
Is there any way I could present a modal controller from my sliding controller regardless which controller is topViewController?
PS. If no, is there any chance that what I want will work with SWRevealViewController instead of ECSlidingViewController? If it's worth, I will take the painful road to switch.
Thank you in advance!
If the ECSlidingViewController is set as the initial view controller in the storyboard, then why are you instantiating another one in your app delegate code? By doing that, you're calling your methods on a different instance of ECSlidingViewController than the one that's put on screen by the storyboard. This is likely the source of your problem. Instead, get a reference to your ECSlidingViewController like this:
self.slidingController = self.window.rootViewController;
Then try,
self.slidingController.topViewController presentModalViewController:controller animated:YES];
or
self.slidingController presentModalViewController:controller animated:YES];
I haven't worked with ECSlidingViewController, so I don't know which of these might work.
Try this
UIViewController *rootViewController = self.window.rootViewController;
// You now have in rootViewController the view with your "Hello world" label and go button.
// Get the navigation controller of this view controller with:
UINavigationController *navigationController = rootViewController.navigationController;
[navigationController.topViewController presentModalViewController:controller animated:YES];
I am trying to push a new root controller to a navigation stack, but using a side reveal menu.
My app delegate has the following:
welcomeViewController = [[MyWelcomeViewController alloc] initWithNibName:#"MyWelcomeViewController" bundle:nil];
navController = [[UINavigationController alloc] initWithRootViewController:welcomeViewController];
navController.navigationBarHidden = YES;
// Then we setup the reveal side view controller with the root view controller as the navigation controller
self.revealSideViewController = [[PPRevealSideViewController alloc] initWithRootViewController:navController];
[self.revealSideViewController setDirectionsToShowBounce:PPRevealSideDirectionNone];
[self.revealSideViewController setPanInteractionsWhenClosed:PPRevealSideInteractionContentView | PPRevealSideInteractionNavigationBar];
// Then we make the window root view controller the reveal side view controller
self.window.rootViewController = self.revealSideViewController;
Once the welcome view controller is displayed, the user logs in. Once logged in the following process runs again from the App Delegate.
self.navController.navigationBarHidden = NO;
[self.navController setTitle:#"Home"];
[self.navController pushViewController:homeViewController animated:NO];
I then have a side view controller setup which is a table view with custom cells setup.
When a row is selected I need to push a new root controller onto the navigation controller. I try this by using the following in the table view for the cell selected.
MyAccountViewController *accountViewController = [[MyAccountViewController alloc] init];
[self.navigationController setViewControllers:[NSArray arrayWithObject:accountViewController] animated:NO];
Unfortunately this does not do anything. If I add the code to the App Delegate and then call the method from the table view controller then it works, however not from the .m file for the table view itself. Adding a log I can see the above is run, just does not do anything.
I am unsure if I need to do anything different on the above. For example, completely pop the views currently shown, then create the navigation controller and PPRevealSideViewController all over again. If I am supposed to, I am unsure how to pop all the current views to then push the new to the window, not from the AppDelegate.
The reason I do not want this in the App Delegate is because it is the incorrect way to approach this, and I would then need a separate method for each new root controller I would like to push from the menu, so the App Delegate would become very large.
Check UINavigationController.h:
#interface UIViewController (UINavigationControllerItem)
#property(nonatomic,readonly,retain) UINavigationController *navigationController; // If this view controller has been pushed onto a navigation controller, return it.
It means when you do myViewController.navigationController you will either get nil if myViewController is not pushed to any navController or the navController reference myViewController is pushed into.
As I understand your tableViewController is not pushed into the navController stack, that means you can't get the navController with tableViewController.navigationController. Instead you'll need to use anyViewControllerInTheStack.navigationController or if the navController is the rootViewController of your keyWindow, by
((UINavigationController*)[[UIApplication sharedApplication] keyWindow].rootViewController)
Add something like this to your AppDelegate.h:
#define XAppDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])
Now you can access any iVar of AppDelegate from any .m file in your project.
MyAccountViewController *accountViewController = [[MyAccountViewController alloc] init];
[XAppDelegate.navController pushViewController:accountViewController animated:NO];
Make sure you add the correct imports.
One more thing: It's good to pop the login window from your navcontroller once you are done Logging in.
Hope this helps.
My application starts off with nothing but a UIWindow. I programmatically add a view controller to self.window in application:didFinishLaunchingWithOptions:.
myViewController = [[UIViewController alloc] init:...];
...
[self.window addSubview:myViewController.view];
[self.window makeKeyAndVisible];
At the same time i kick off a background process:
[NSThread detachNewThreadSelector:#selector(startupOperations) toTarget:self withObject:nil];
The startupOperations look something like this:
NSAutoreleasePool *threadPool = [[NSAutoreleasePool alloc] init];
// Load data
...
// When your done, call method on the main thread
[self performSelectorOnMainThread:#selector(showMainViewController) withObject:nil waitUntilDone:false];
// Release autorelease pool
[threadPool release];
showMainViewController removes myViewController, creates a UITabBarController and sets it as the window's main view:
[self.myViewController.view removeFromSuperview];
self.myViewController = nil;
tabBarController = [[UITabBarController alloc] init];
...
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
Questions:
All the view controllers are returning YES for shouldAutorotateToInterfaceOrientation:. Rotation works fine for myViewController but as soon as the tabBarController is made visible, rotation stops working and interface appears in Portrait. What's the reason behind this behavior?
Also, in iOS 4.x, UIWindow has rootViewController property. What's the role of this property? The new templates use rootViewController instead of [self.window addSubview:...]. Why is that?
Pretty strange. I tried and simulate your "view flow" in a simple tab bar based project and autorotation effectively works after removing the initial controller and adding the tab bar controller's view as a subview.
The only condition I found where it did not work is when self.window did contain a second subview that I did not remove. Could you check at the moment when you execute
[self.window addSubview:tabBarController.view];
what is self.window.subview content?
If that does not help, could you share in your question how you initialize the UITabBarController and UITabBar?
As to your second question, as you say rootViewController is the root controller for all the views that belong to the window:
The root view controller provides the content view of the window. Assigning a view controller to this property (either programmatically or using Interface Builder) installs the view controller’s view as the content view of the window. If the window has an existing view hierarchy, the old views are removed before the new ones are installed.
(Source)
You can also use that, but take care of assigning it already in applicationDidFinishLaunching, otherwise, if you "manually" add a subview and later change this property, it will not remove the subview you explicitly added.