How to assign NSManagedObjectContext from AppDelegate to ViewControllers in TabBased application? - ios

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
}

Related

Setting a RootViewController with UINavigationController Programmatically

I have a program with a Navigation Controller and a default RootViewController. If I do nothing programmatically, the app launches and the RootViewController works as I expect, such as what the storyboard below denotes:
The issue that I have is by incorporating the Optional Start ViewController. What I want is this: In my AppDelegate (didFinishLaunchingWithOptions), I want to have code like this:
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"OptionalStartViewController"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
To first show the Optional Start ViewController. Then, after the user has finished with the Optional viewcontroller, they can then display the RootViewController.
So in the Optional Start ViewController, I've added code like this to show the Root View Controller:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"RootViewController"];
[self appDelegate].window.rootViewController = viewController;
[[self appDelegate].window makeKeyAndVisible];
This all works except the RootViewController, when shown, does not have the navigation controls as expected (i.e. the view is shown without navigation controls).
I've also tried the code below (using UINavigationController instead of ViewController) with the same results...
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UINavigationController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"];
[self appDelegate].window.rootViewController = viewController;
[[self appDelegate].window makeKeyAndVisible];
One other twist... there could be several optional start view controllers.
Any ideas?
Delete the UINavigationController
select the controller ("optional start view controller" in our case)
click Editor >> Embed In >> Navigation Controller
Now select the Navigation Controller and Right Side Utility area, Select the option Is Initial View Controller
If you want to change the root view controller dynamically then its better to do it programmatically, in didFinishLaunchingWithOptions, Get the window instance , initialize navigation controller with the root view controller and then set windows root view controller to navigation controller.
Here is the code.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
OptionalFirstViewController *optionalFirstViewController = [[OptionalFirstViewController alloc] initWithNibName:#"OptionalFirstViewController" bundle:nil];
UINavigationController *homeNavigationController = [[UINavigationController alloc] initWithRootViewController:optionalFirstViewController];
[optionalFirstViewController release];
self.window.rootViewController = homeNavigationController;
[homeNavigationController release];
[self.window makeKeyAndVisible];
return YES;
}
and make sure that you uncheck Is Initial View Controller for all view controllers in story board
Hope this helps
Without using storyboard we can set programmatically in AppDelegate Class, just write down these lines of code in AppDelegate.
AppDelegate.h
#property (strong, nonatomic) UIStoryboard *storyboard;
#property (strong, nonatomic) UINavigationController *navigationController;
AppDelegate.m
if(self.window == nil)
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
if(self.navigationController == nil)
self.navigationController = [[UINavigationController alloc]init];
if(self.storyboard == nil)
self.storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.navigationController.navigationBarHidden = YES;
// Here we can check user is login or not also,
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *ivc = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:ivc animated:YES];
self.window.rootViewController = ivc;
[self.window setRootViewController:self.navigationController];
[self.window makeKeyAndVisible];
In Swift Version
var window: UIWindow?
var storyBoard :UIStoryboard?
var navigationController : UINavigationController?
var mainController :MainViewController = MainViewController()
if window == nil {
window = UIWindow(frame: UIScreen.main.bounds)
}
if navigationController == nil {
navigationController = UINavigationController()
}
if storyBoard == nil {
storyBoard = UIStoryboard(name: "Main", bundle:nil)
}
navigationController?.setNavigationBarHidden(true, animated: true)
// storyboard with identifer
mainController = storyBoard?.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
navigationController?.pushViewController(mainController , animated: true)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
You can't set a new root view controller to UINavigationController after it is initialised. You should modify viewControllers array of UINavigationController according to your needs.
If you want the optional VC to be root VC, create #[optionalVC] and set it as viewControllers array of UINavigationController.

How to reference certain View Controllers

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

how do i add a uiviewcontroller before the navigation controller when using the master-detail template and core data

I have tried almost everything i can think of to add a uiviewcontroller prior to the navigation controller but every time it crashes due to core data managed context method. I have attached the piece of code that is my problem as I can't remove the navigation controller from being the rootviewcontroller whilst using the core data.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
MasterViewController *controller = (MasterViewController *)navigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;}
I found the answer to my problem.
Delete the above code from didFinishLaunch in the appdelegte
Import app delegate into view controller
add this code to view did load in view controller
self.managedObjectContext = [self managedObjectContext];
if (self.managedObjectContext == nil) {
self.managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}

Accessing UITabBarController from Appdelegate

I am trying to access my UiTabBarController from a UIViewController that is in UIWindow,
Since its not part on UITabBarController - using self.tabBarController.. won't work as it will be nil.
So I tried this code:
BBAppDelegate *appDelegate = (BBAppDelegate *)[[UIApplication sharedApplication] delegate];
UITabBarController *tabBarController = appDelegate.window.rootViewController.tabBarController;
When it step through the code with the debugger - I can see appDelegate does have a tabBarController and it is not nil. However on the next line
UITabBarController *tabBarController = appDelegate.window.rootViewController.tabBarController;
This results in tabBarController instance being nil and the tabBarController in the appDelegate still have a memory address assigned to it and its not nil.
What am I doing wrong here?
Edit
Here is what my debugger looks like:
Thanks!
Edit 2
This is who I setup the side menu which is added to rootViewController
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main_iPhone"
bundle: nil];
BBFilterViewController *loginController=[[UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"FilterViewController"]; UINavigationController *navController=[[UINavigationController alloc]initWithRootViewController:loginController];
self.tabBarController = [mainStoryboard instantiateViewControllerWithIdentifier: #"HomeScreen"];
MVYSideMenuOptions *options = [[MVYSideMenuOptions alloc] init];
options.contentViewScale = 1.0;
options.contentViewOpacity = 0.5;
options.shadowOpacity = 0.0;
MVYSideMenuController *sideBarController = [[MVYSideMenuController alloc]initWithMenuViewController:navController contentViewController:self.tabBarController options:options];
self.window.rootViewController = sideBarController;
[self.window.rootViewController addChildViewController:self.tabBarController];
[self.window makeKeyAndVisible];
If you have tab bar controller as root view controller you can access it like:
UITabBarController *tabBarController = (UITabBarController *)appDelegate.window.rootViewController;
//Extended
Based on update to your question you should be able to get reference to tab bar controller from last child root view controller array:
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController.childViewControllers.lastObject;
From you debugger I think it should be UITabBarController *tabBarController = appDelegate.tabBarController;

SimpleDrillDown example with TabBarController

I have been experimenting with the SimpleDrillDown example from Apple and attempted to put it into a tab bar. The problem is the view now doesn't show, and I know it is the following code in the App Delegate that is causing it. I am struggling with changing it to fit with the tabbar and would appreciate some pointers.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the data controller and pass it to the root view controller.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
RootViewController *rootViewController = (RootViewController *)[[navigationController viewControllers]objectAtIndex:0];
DataController *controller = [[DataController alloc] init];
rootViewController.dataController = controller;
self.dataController = controller;
}
I have replaced it with the following but this line EatCatTVC *rootViewController = (RootViewController *)[[navigationController viewControllers]objectAtIndex:0]; throws an error
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UITabBarController *tabBar = (UITabBarController *)self.window.rootViewController;
// Create the data controller and pass it to the root view controller.
EatCatTVC *rootViewController = (RootViewController *)[[navigationController viewControllers]objectAtIndex:0];
DataController *controller = [[DataController alloc] init];
rootViewController.dataController = controller;
self.dataController = controller;
return YES;
}
Your code is failing because you are accessing non-existent object
EatCatTVC *rootViewController = (RootViewController *)[[navigationController viewControllers]objectAtIndex:0];
on this line navigationController doesn't exist in your "modified" version.
Make sure that "rootController" is set to UITabBarController class (I assume that you did setup this in Interface Builder).
And then use setViewControllers:animated: to provide the UITabBarController' instance with (for instance)UIViewController` instances that are meant to be present.

Resources