I've got an app using Core Data where I'm creating a managedObjectContext in the app delegate.
I want to pass that managedObjectContext to two view controllers on my storyboard so they are using the same managedObjectContext to save and fetch to and from.
I can access the first view controller with:
self.window.rootViewController
But the second view controller I want to access is then after a segue from the first and no reference is returned from it.
I tried:
instantiateViewControllerWithIdentifier:
But that creates a new instance of the view rather than allowing me to access the second view controller that appears after the segue.
So my question is, how can I access the second view controller?
Or (as I'm very new to this) is there a better way to be managing/passing the data between the view controllers?
Thanks in advance.
Or (as I'm very new to this) is there a better way to be managing/passing the data between the view controllers?
It depends on the data you're trying to pass around. In this case, you want to give your view controllers access to your Core Data managed object context. Because this is something you're going to need throughout the lifespan of your app it would be better to have your view controllers access it via your application delegate.
You can do this via [[UIApplication sharedApplication] delegate] - however, you may need to typecast it to avoid compiler warnings, or alternatively you might want to create a macro that returns the managed object context to save you time and make your code a little more readable.
If you told XCode you wanted to use Core Data when you created the project you should have the methods to retrieve your object context already in your app delegate. If not, you'll need to create them.
To create a macro to save you having to write out [[UIApplication sharedApplication] delegate] every time you need to access the managed object context, check out this answer: Short hand for [[UIApplication sharedApplication] delegate]?
You can go through this :-
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
MasterViewController *result;
//check to see if navbar "get" worked
if (navigationController.viewControllers) {
//look for the nav controller in tab bar views
for (UINavigationController *view in navigationController.viewControllers) {
//when found, do the same thing to find the MasterViewController under the nav controller
if ([view isKindOfClass:[UINavigationController class]])
for (UIViewController *view2 in view.viewControllers)
if ([view2 isKindOfClass:[MasterViewController class]])
result = (MasterViewController *) view2;
}
}
Related
I have a simple iOS application with one UIViewController beneath a UINavigationController. The UIViewController has an IBOutlet for an NSManagedObjectContext.
The AppDelegate has an IBOutlet for the nav controller - but not the view controller. The view controller is automatically instantiated ala the XIB process (as a child of the nav controller).
With this setup, how does one cleanly assign or pass the app delegate's NSManagedObjectContext to the view controller's IBOutlet property. There is a nav controller in the way :) and the app delegate doesn't have a direct property for the UIViewController.
It is a weird problem in that, I want to link a property from one XIB component to another component's property. Most of the XIB work I've done takes a property and points it to an object in the XIB which in turn - gets instantiated ala the normal process but in this case, the context is being created correctly in the app delegate, I just want to pass it on to the view controller when it instantiates it.
You don't need to pass it, just grab it from the app delegate as required:
#import "MyAppDleegate.h"
NSManagedObjectContext* moc = [(MyAppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext];
Apple's docs recommend that you pass references to your managed object context to the classes the require them instead of referencing it from your app delegate.
Here's what the application:didFinishLaunchingWithOptions: looks like in one of my Core Data projects.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
LocationsViewController *lvc = (LocationsViewController *)self.navigationController.topViewController;
lvc.managedObjectContext = self.managedObjectContext;
assert(lvc.managedObjectContext != nil);
[self.window addSubview:self.navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
You'll see that I also start with a UINavigationController with a single root view controller.
You've got the right idea, but the problem you're wrestling with seems to be entirely of your own creation. You say that your app delegate has an outlet for the navigation controller, but not for the nav controller's root view controller, because you've set up your nib such that the view controller is created when the nib is loaded. There's nothing wrong with that, but there's also no reason that the app delegate shouldn't have an outlet for that controller. Indeed, the entire reason for outlets is to get references to things that are loaded from a nib.
Add an outlet to your app delegate for your root view controller, and connect it. The app delegate can then give the controller a reference to the managed object context.
With respect to your question about multiple view controllers, I wonder what sort of real-world app might have view controller (A), which needs data, load another view controller (B) which doesn't need any data, followed by a third (C) which again needs data? A realistic example might help, if you have one.
Remember that you don't have to pass the entire managed object context to each successive view controller. You can instead pass just the part of the model that the controller will need to do its work by passing a managed object.
I have an app which is based on the Utility template (where you flip over the view to see another). On the first view there is a login screen, then it flips over to reveal a UITabBar style interface.
I'm having trouble working out how to pass the managedObjectContext from the App Delegate (where it is created) all the way through to each of the Tab Bar's views.
App Delegate's managedObjectContext get passed to FrontLoginViewController which gets passed to BackViewTabBarViewController .. where next?
The BackViewTabBarViewController nib has a UITabBarController with a UINavigationController for each tab.
Sounds like the managedObjectContext is defined in your AppDelegate. If so, then...
From whatever viewController you want... just call
MyApplicationDelegate *appDelegate = (MyApplicationDelegate *)[[UIApplication sharedApplication] delegate];
Then use...
appDelegate.managedObjectContext
whenever you need the managedObjectContext. Change the MyApplicationDelegate to your AppDelegate and you should be good to go.
I've ran into this same problem, i'll share my solution.
First you need a reference to the Nav Controller in the Tab Bar in the nib file, make sure you connect it up.
IBOutlet UINavigationController *navigationController;
Then, get the Controller as recommended in the support docs and send it the managedObjectContext:
SavedTableViewController *saved = (SavedTableViewController *)[navigationController topViewController];
saved.managedObjectContext = self.managedObjectContext;
Alex (from another post) is right, "You should generally stay away from getting shared objects from the app delegate. It makes it behave too much like a global variable, and that has a whole mess of problems associated with it."
I just started developing with the iPhone SDK and I have a problem with switching to another tab with the UITabBar.
This is my current code, and it works so far:
myAppAppDelegate *appDel = (myAppAppDelegate *)[[UIApplication sharedApplication] delegate]
[appDel.tabBar setSelectedViewController:[appDel.tabBar.viewControllers objectAtIndex:5]];
But if i go to the more tab and rearrange the tabbar items, the index of the viewControllers change too. Is there any possibility how I could solve this problem?
First of all, if you ever find yourself typing this:
(myAppAppDelegate *)[[UIApplication sharedApplication] delegate]
You can probably benefit from a better design. This code probably comes from a view controller, in which case you are calling out to the App delegate from a view controller, and dealing with stuff you shouldn't have knowledge of (the tab bar).
A better design is to delegate out to the app delegate, and the app delegate switches the tab for you. The app delegate should have references to the actual view controllers in the tab bar (you can hook these up via IB if not) so you can call setSelectedViewController: with the correct object, rather than indexing into the tab bar's array:
/* Somewhere in the app delegate */
- (void)selectFooBarController {
[self.tabBar setSelectedViewController:self.fooBarController];
}
Now if you don't want to bother with delegation you can just put a method on the app delegate (like the one above) and your original code becomes:
myAppAppDelegate *appDel = (myAppAppDelegate *)[[UIApplication sharedApplication] delegate]
[appDel selectFooBarController];
Again you will need to add IBOutlet properties to your app delegate which you connect to the fooBarController etc. in Interface Builder. This will let you directly reference them rather than grabbing them out of an array.
The most straight forward means I can think off relies on the fact that when you application first starts, unless you are doing something to save the re-ordering, you could save off the initial list of UIViewControllers:
initialOrdering = [[appDel.tabBar viewControllers] copy];
Where 'initialOrdering' is an NSArray* which you would then use instead of appDel.tabBar.viewControllers in the code you posted.
I have developed a small iPhone application by using singleton that I use to navigate through the views. Here is a sample method from my singleton class.
+ (void) loadMenuController:(NSMutableArray *)menuItems{
MenuViewController *menuViewControler = [[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:nil];
[menuViewControler setMenuItems:menuItems];
RootViewController *root = (
P2MAppDelegate *appDelegate = (P2MAppDelegate*) [[UIApplication sharedApplication] delegate];
UINavigationController *navController = [appDelegate navigationController];
[navController pushViewController:menuViewControler animated:YES];
[menuViewControler release];
}
Now my requirement has changed to require a tab view controller . I could change my application delegate to a tabview controller but I still need to navigate inside each tab. I am unable get a clue how to navigate from my singleton class.
Please guide me. Please let me know if my query is not clear.
Thanks in advance.
Regards,
Malleswar
You shouldn't be using a singleton to manage the interface and even if you did, you wouldn't put the UI logic in a class method. You need to rethink your design from scratch.
The normal pattern is to hold the navigation controller or the tabbar controller as an attribute of the application delegate. The app delegate itself should not be a subclass of any controller but just a NSObject subclass that implements the application delegate protocol.
Look at the Apple supplied template projects in Xcode to see the quick and dirty way to structure apps built around navigation and/or tabs.
Singletons should only be used when you have to ensure that one and only one instance of class is alive at one time. You don't need to make your own singleton to manage the UI. The application delegate is attached to the application object which is itself a singleton. This means the app delegate provides all the restriction on class for the UI you might need. You don't need another singleton in addition to that.
Overuse of singletons is dangerous and can cause your design to get trapped in a dead end resulting in a massive rewrite. Think carefully before employing them.
I'm experimenting with ViewControllers & NavigationControllers in Interface Builder trying to get a better grasp of what's tied to what and why... I'm struggling with a scenario that has confused me. Hopefully someone can set me straight...
Say I start with your typical iPhone template View-Based Application and I display a view which is handled by view controller (viewController). Then after a certain event I'd like to replace that view with a "typical" Navigation-Based View (rootVC). I'd like to create as much as possible in IB. My questions have to do with how to show rootVC and remove all traces of the previous viewController as user will never need to return and where/how to wire in the navController in IB. Currently when it's time to show the rootVC I do the following in my viewController:
RootVC *rvc = [[RootVC alloc] initWithNibName:#"RootVC" bundle:nil];
[rvc.view setFrame:[[UIScreen mainScreen] applicationFrame]];
ViewTestAppDelegate *appDelegate = (ViewTestAppDelegate *)[[UIApplication sharedApplication] delegate];
self.rootVC = rvc;
[rvc release];
[appDelegate.viewController.view removeFromSuperview];
[appDelegate.window addSubview:rootVC.view];
[appDelegate.viewController release];
rootVC displays except viewController still has a retain count of 1?!?
Also, where should rootVC's navigationController be instantiated? Having started with the View-Based template the MainWindow.xib contains an object for the viewController (which has its own ViewController.xib) an appDelegate and a UIWindow. My RootVC.xib contains a UITableView. Do I need yet another intermediary view controller that will have another ApplicationDelegate object that I wire up to a UIWindow object and a UINavigationController? The View Controller that comes along with IB's Navigation Controller object would then be set to my RootVC class?
Sorry for the verbosity. It's difficult for me to explain. Because some objects in IB are proxies and some are "real" it's sometimes confusing (to me) when trying "new" things out what's required, where & when. Basically I want to know to go about setting up one view leading to another with no way back to first view. 2nd view basically becomes the "main" root spawning off in many directions...
I would recommend using the navigation-based iPhone application template and presenting your one-time view as a modal view on top of the root view.
I was able to figure it out by putting a reference to the viewController in the MainWindow nib and then autoreleasing the viewController after I added the navigationController & rootVC to the UIWindow. Learned another thing or two about IB along the way. Pretty powerful...