I'm trying to reference a UITabController from my app delegate, even though it isn't my rootViewController. How do I do it?
UITabBarController *tabBarController =
(UITabBarController *)self.window.rootViewController;
UINavigationController *navigationController =
[[tabBarController viewControllers] objectAtIndex:1];
DocumentsViewController *ViewController =
[[navigationController viewControllers] objectAtIndex:0];
I want to change the first line of code so it doesn't reference the "rootViewController" but directly references my UITabBarController, because I have a start screen that I want to use for the app.
Declare your UITabBarController in the .h of your AppDelegate.
Get a reference to your AppDelegate:
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
Then you can do:
delegate.tabBarController;
Or you could do:
[(AppDelegate*)[UIApplication sharedApplication] delegate] tabBarController];
Also, make sure to include "AppDelegate.h" in your rootViewController/
EDIT:
Add this to the .h of your rootViewController class so that it is publicly accessible:
#property SecondViewController *mySecondViewController;
Now, when you instantiate your SecondViewController before you present it modally make sure to do it like this:
self.secondViewController = [[SecondViewController ...
You should now be able to reference your secondViewController from your AppDelegate like this:
self.rootViewController.mySecondViewController
Related
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
Apple documentation says that any application using a split view controller should make it as a root view controller. But i am struck at a state where, my login screen should redirect me to a split view controller. Is there a way to achieve this?
I am Using storyboards and new to programming. Kindly help.
One quite common way to solve this issue to change the rootViewController of your applications main UIWindow (which again is a property of your AppDelegate) after a successful login.
So, the initial view controller of your app needs to be your LoginViewController that handles the login. After a successful login, you can do something like this:
- (void)switchToMainInterface
{
// Change the root view controller of the application window to the main storyboard
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UISplitViewController *mainSplitViewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"MainSplitViewController"];
UIWindow *mainApplicationWindow = [[[UIApplication sharedApplication] delegate] window];
mainApplicationWindow.rootViewController = mainSplitViewController;
}
Note that this code is just dummy code to make my suggestion a bit more tangible, it makes the following assumptions:
you have a Storyboard called Main in your application bundle
within this Main Storyboard you have a UISplitViewController with the Storyboard ID MainSplitViewController so that you can instantiate it programmatically
you need to import AppDelegate.h to get access to the root UIWindow
Link your LoginViewController to a UIViewcontroller. In this controller drag an UIContainerView, and embed your UISplitViewController in it.
I created a custom segue class and implemented the following code. I am not sure what it does to my application. It seems a bit high level code to me as I am an amature but it works fine. Hope you find it useful.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Override point for customization after application launch.
// UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
// UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
// splitViewController.delegate = (id)navigationController.topViewController;
return YES;
}
Commented the above code, I believe this is to pause UISplitViewController from loading into UIWindow.
And my custom segue --> segue.m is as follows..
#import "Seague.h"
#implementation Seague
-(void)perform
{
UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *)self.destinationViewController;
UISplitViewController *splitViewController = (UISplitViewController *)destinationViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
UIWindow *window = [UIApplication sharedApplication].keyWindow;
window.rootViewController = destinationViewController;
window.rootViewController = sourceViewController;
[UIView transitionWithView:sourceViewController.view.window duration:0.5 options:UIViewAnimationOptionTransitionNone animations:^{
window.rootViewController = destinationViewController;
} completion:^(BOOL finished){}];
}
#end
This segue is triggered when my login button is pressed and the login details are valid.
My rootViewController is the viewController that has my login button and not UISplitViewController.
Reference: This is not a code I wrote. Found it somewhere on web after searching for 2 days. Will update the source link for reference soon.
Thankyou all for your responses :)
newbie type of question here.
Since XCode doesn't provide project template for TabBased application with Core Data, so I have to go cutting and pasting Core Data stack from other templates to my TabBased application.
This is how to assign NSManagedObjectContext object from AppDelegate to MasterViewController in Master-Detail application template:
// AppDelegate.m (Master-Detail template)
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UINavigationController *navigationController =
(UINavigationController *)self.window.rootViewController;
MasterViewController *controller =
(MasterViewController *)navigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
How to assign NSManagedObjectContext from AppDelegate to ViewControllers in TabBased application?
If the tab bar controller is the root view controller and
the "master view controller" is on the first tab:
UITabBarController *tbc = (UITabBarController *)self.window.rootViewController;
MasterViewController *controller = (MasterViewController *)tbc.viewControllers[0];
controller.managedObjectContext = self.managedObjectContext;
Update: If the first tab uses a navigation controller, you just have to insert one step:
UITabBarController *tbc = (UITabBarController *)self.window.rootViewController;
UINavigationController *nc = tbc.viewControllers[0];
YourViewController controller = (YourViewController *)nc.topViewController;
controller.managedObjectContext = self.managedObjectContext;
Create a property on your View Controller:
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext
Then say, for example you want to assign this for all view controller. You can do it by looping through the viewControllers of the UITabBarController.
UITabbarController *tabBarController = (UITabBarController *)self.window.rootViewController;
for (UIViewController *viewController in tabBarController.viewControllers) {
viewController.managedObjectContext = self.managedObjectContext
}
I have two issues that I don't understand and am hoping that someone can help.
This code doesn't work for taking my existing UINavigationController hierarchy from a split view controller and taking over the screen with it. I just get a dark screen
UINavigationController* myself = self.navigationController;
[myself removeFromParentViewController];
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"QuestionnaireViewController"];
[myself pushViewController:controller animated:YES];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
app.window.rootViewController = myself;
However, this code does work. Why can I set the rootViewController to a new UINavigationController but not self.navigationController?
UINavigationController *navController = [[UINavigationController alloc] init];
UINavigationController* myself = self.navigationController;
[myself removeFromParentViewController];
navController.viewControllers = myself.viewControllers;
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"QuestionnaireViewController"];
[navController pushViewController:controller animated:YES];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
app.window.rootViewController = navController;
My second issue is in restoring the navigation controller to the splitViewController when the user goes "back". I know from experience that I can assign a new UINavigationController to the detailView, but I cannot assign self.navigationController.
I think the issues are the same issue. For some reason a new UINavigationController is not the same as a UIView's navigationController. Why?
Meddling with UIWindow is not very safe.
Depending on what you are trying to achieve, I can think of 2 rather simple options
a) iOS 5.1+ has an option to show/hide the RootViewController of your split and show with a swipe gesture, and work with that
b) Create your own UIViewController that emulates UISplitViewController, and hide the left part whenever you need to
I will try to explain this as best as I can.
My application has a TabBarController which functions as the main navigation
I have a modal view that I segue to to add a list. that screen can be reached from 2 different viewcontrollers.
From the main route I simple just close the modal and all is fine. However from the second route I need to be able to open up an entirely new ViewController.
The issue that I am having is that I can not seem to open that ViewController with the TabBar and NavBar included.
This is the code I am currently playing with to try to get it to work.
UITabBarController *tabController = [self.storyboard instantiateViewControllerWithIdentifier:#"MainInterface"];
tabController.selectedIndex = 1;
//_window.rootViewController = tabController;
UINavigationController *groceryNavController = [self.storyboard instantiateViewControllerWithIdentifier:#"MainNavController"];
UIViewController *groceryViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"GroceryViewController"];
UIViewController *currentVC = self;
[currentVC.navigationController pushViewController:groceryViewController animated:YES];
One way to to do it is through the delegate. If in the delegate, the relevant navigation controller is called:
self.navigationController
Then you would have to do:
YourAppDelegate *delegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate.navigationController pushViewController:groceryViewController animated:YES];
(replace "YourAppDelegate" with the actual name of your app delegate)