UITabbarcontroller in IOS5 throws UIViewControllerHierarchyInconsistency exception - objective-c

I have the following code for the UITabbarcontroller:
NSMutableArray *arr = [[NSMutableArray alloc] init];
tabBarController = [[UITabBarController alloc] init];
FirstViewController *firstview = [[FirstViewController alloc] init];
[tabBarControllerViews addObject:firstview];
[firstview release];
SecondViewController *secondview = [[SecondViewController alloc] init];
[tabBarControllerViews addObject:secondview];
[secondview release];
[tabBarController setViewControllers:arr animated:YES];
[arr release];
self.view = tabBarController.view;
This code runs fine on IOS4. I tried it on IOS5 beta and get the following error when tapping on a UITabbarItem:
*** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency',
reason: 'child view controller:<FirstViewController: 0x6e03be0> should have parent view
controller:<MainViewController: 0x6816d20> but actual parent is:<UITabBarController: 0x6b0c110>'

replace:
self.view = tabBarController.view;
with:
[self.view addSubview:tabBarController.view];
This will also be backwards compatible with IOS3&4.

Had the same pattern (and problem) in my code. Joe's solution didn't work for me. Looking at the snippet, I'm guessing that you derive a class from UIViewController to allow you to customize something.
The thing to do here, and it is quite simple, is to derive from UITabBarController rather than UIViewController, don't create tabBarController, and anywhere you reference tabBarController, substitute self.
5 minutes and you're no longer throwing the inconsistency exception and you remain backwards compatible with iOS 4. You can still do all of your customization in your derived class (monkeying with the nav controller, etc).
If you have built a complex derivation of UIViewController you need to use, this could be more work.
One small gotcha - if you override LoadView, you'll find that it gets called during the init for the UITabBarController. Makes it hard to set members prior to LoadView, so you may need to split up your initialization.
Good luck!

You cannot push or present a UITabbarViewController. Is your First View Controller a UITabBarController ?

I struggled with the same problem.
When you create a new Master-Detail Application(without story board), you can see this codes below from AppDelegate.m.
MasterViewController *masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
"BE NOT DEPENDENT ON MainWindow"
Just start from your own ViewController and set it to delegate.
And don't forget to unlink view from MainWindow.xib else the view will called 2 times.

Related

PresentModalViewController not showing TabBar

I'm trying to go from one xib to another and I'm using TabBar.
When I move from xib to xib with PresentModalViewController I lose the TabBar.
When I use this way, it fail (like force close in android):
FirstViewController *fvc = [[FirstViewController alloc]initWithNibName:#"FirstViewController" bundle:nil];
[fvc setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
fvc.userSelectedLatitude = saveLatitude;
fvc.userSelectedLongitude = saveLongtitude;
UITabBarController *tabControl = [[UITabBarController alloc] initWithNibName:fvc bundle:nil];
[self presentModalViewController:tabControl animated:NO];
When I use:
UITabBarController *tabControl = [[UITabBarController alloc] initWithNibName:#"FirstViewController" bundle:nil];
I get black screen with TabBar.
Since it all fail I guess it is not the right way.
So, what is the right way to do it?
The code above crashes because you are trying to pass a view controller instead of an NSString object in the initWithNibName:bundle: method.
The way to do it depends of what you really want to do. Do you want to present the xib in a modalViewController with or without a tabBar?, or simply present the view controller modally?.
UPDATE:
Fine, you have to create first your view controllers associated to each tabBar button (like you have been doing until now), after, add these view controllers to your tabBar and then present the tabBarController modally. Like this:
FirstViewController *fvc = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
fvc.userSelectedLatitude = saveLatitude;
fvc.userSelectedLongitude = saveLongtitude;
UITabBarController *tabControl = [[UITabBarController alloc] init];
[tabControl setViewControllers:[NSArray arrayWithObjects:fvc, nil]];
[tabControl setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:tabControl animated:NO];
I think this code should work. So, try it and tell us if something goes wrong.
With UITabBarController, there is no need to manually present viewControllers or call code to switch the views. This is handled for you.
All you need to do is set the viewControllers property of the UITabBarController. Like so:
[tabBarController setViewControllers:[NSArray arrayWithObjects:view1, view2, nil]];

UINavigationController for table inside of UITabController

my app is built with a UITabController and works as imagined. However, for one of the views within my UITabBar, I would like to add a table that when something is pressed will take me somewhere. And I would like to do this just within this one view.
I know how to build a table and populate and get it to go somewhere but my issue is I can't seem to get my app to run with the table. I feel like my connections are off and specifically with appDelegates. I already had two appDelegate files (.h & .m) before adding the UINavigationController so from here I really don't know what to do. I took apple's simpleTableView tutorial files and copied them over to mine. It still crashes. I even copied there appDelegate files (so now I have 4) but the same deal. This is the error I am getting but in general I just feel lost with the delegates and connections.
2011-12-12 12:08:50.302 TabbedCalculation[68713:207] * Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key delegate.'
* Call stack at first throw:
If anyone can offer any help, it would be much appreciated.
Thanks!
P.S. I have changed within the mainWindow.xib of the UITabController to point one of the tabs to the appropriate class and xib file so that is not the issue but I have noticed that many tutorials want within the app delegate this line to the navController:
[window addSubview:[navigationController view]];
but I have already set it to the tabBarController.
Your app can only use one set of app delegate files. So copying over a the example's app delegate files does not mean they are being utilized. You need a navigation controller inside the specific tab you want to contain the tableview. Here is an example of a navigation controller inside a tab bar controller, by modifying didFinishLaunchingWithOptions in the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
AllTaskViewController *view1 = [[AllTaskViewController alloc] initWithNibName:#"AllTaskView" bundle:nil];
view1.title = #"All Tasks";
TodayTaskViewController *view2 = [[TodayTaskViewController alloc] initWithNibName:#"TodayTaskView" bundle:nil];
view2.title = #"Today's Tasks";
HistoryViewController *view3 = [[HistoryViewController alloc] initWithNibName:#"HistoryView" bundle:nil];
view3.title = #"History";
SettingsTableViewController *view4 = [[SettingsTableViewController alloc] initWithNibName:#"SettingsTableView" bundle:nil];
view4.title = #"Settings";
UINavigationController *nav1 = [[UINavigationController alloc] initWithRootViewController:view1];
UINavigationController *nav2 = [[UINavigationController alloc] initWithRootViewController:view2];
UINavigationController *nav3 = [[UINavigationController alloc] initWithRootViewController:view3];
UINavigationController *nav4 = [[UINavigationController alloc] initWithRootViewController:view4];
[view1 release];
[view2 release];
[view3 release];
[view4 release];
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:nav1, nav2, nav3, nav4, nil];
[nav1 release];
[nav2 release];
[nav3 release];
[nav4 release];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
Note: All 4 view controllers have an individual navigation controller, and each one is a custom view controller. I used nibs here, but you don't necessarily have to. And the app itself has no main window, you would need to modify this slightly if you are using a main window for the app.

adding subview of another class

iv created a class with xib so i can access it throughout my app. The class basically holds a nib with has three uiviews and a few buttons buttons+labels. Now im calling class A (the one with 3 view etc) from classB but every time i addsubview to self.view nothing happens. any help appreciated.
ive done the following in class B.h
#import "PlayResultViewController.h"
PlayResultViewController *playResultViewController;
in classB.m
//viewdidload
playResultViewController = [[PlayResultViewController alloc]init];
//some random method
[placeholderView addSubview:playResultViewController.loseView];
You are missing the initWithNibName to start with, here are some examples
With a Navigation controller u can use
BViewController *bController = [[BViewController alloc] initWithNibName:#"BViewController" bundle:nil];
[self.navigationController pushViewController:bController animated:YES];
[bController release];
without UInavigation controller you can test with
BViewController *bController = [[BViewController alloc] initWithNibName:#"BViewController" bundle:nil];
self.view = bController;
// or alternatively self.view = bController.view;
[bController release];
You need to tell it which nib to load....
playResultViewController = [[PlayResultViewController alloc] initWithNibName:#"Mynib" bundle:nil];

UINavigationController: Simplest Example

I'm trying to do very simple example of a UINavigationController. Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
This next line works, or at least doesn't blow up.
navController = [[UINavigationController alloc] initWithRootViewController:self];
self.title = #"blah";
PageOneController *one = [[[PageOneController alloc]init] autorelease];
Example 1. THIS LINE DOES NOTHING
[navController pushViewController:one animated:NO];
Example 2. THIS LINE WORKS (but no nav controller, of course)
[self.view addSubview:one.view];
}
Why am I unable to push ViewController instances onto the navController and see the screen change?
Note: I realize that I might have my concepts backwards and I don't need to have my view referencing a UINavigationController... or something.
- (void)viewDidLoad {
[super viewDidLoad];
PageOneController *one = [[[PageOneController alloc]init] autorelease];
one.title = #"blah";
navController = [[UINavigationController alloc] initWithRootViewController:one];
[self.view addSubview:navController.view];
}
The basic idea behind it is that a navigation controller's root view controller is the controller which view will be displayed first in the navigation controller hierarchy. The root controller is not the view controller that you plug the navigation controller into. Hope this helps.
I'm just restating #E-ploko's answer, which is 100% correct (which is why I marked it best answer).
You need more views (and view controllers) to use the UINavigationController. One of them houses the UINavigationController, and its rootViewController is the first page of the series (the one that has no "back").
I got rid of the external dependencies for the code sample: obviously this is monolithic sample code, not monolithic real code.
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController *one = [[UIViewController alloc] init];
[one.view setBackgroundColor:[UIColor yellowColor]];
[one setTitle:#"One"];
navController = [[UINavigationController alloc] initWithRootViewController:one];
// here 's the key to the whole thing: we're adding the navController's view to the
// self.view, NOT the one.view! So one would be the home page of the app (or something)
[self.view addSubview:navController.view];
// one gets reassigned. Not my clearest example ;)
one = [[UIViewController alloc] init];
[one.view setBackgroundColor:[UIColor blueColor]];
[one setTitle:#"Two"];
// subsequent views get pushed, pulled, prodded, etc.
[navController pushViewController:one animated:YES];
}

How is it possible to come back to the same page?

I am new at Objective C. I am just trying to build an iphone app. I have created some NIB file, and i have gone to other NIB file by creating an object and using this code:
scoreViewController *sviewController = [[scoreViewController alloc] initWithNibName:#"scoreViewController" bundle:nil];
self.scoreView = sviewController;
[sviewController release];
// Setup the animation
[self.navigationController pushViewController:self.scoreView animated:YES];
Now I want to come back to the same page. For this case I have done the same work, but it does not work when I add the previous page header file name.
mainViewController *mainviewController = [[mainViewController alloc] initWithNibName:#"mainViewController" bundle:nil];
self.mcoreView = mainviewController;
[mainviewController release];
// Setup the animation
[self.navigationController pushViewController:self.mcoreView animated:YES];
So, I will be most grateful if you were so nice to post your comment.
I am not 100% sure what you are asking, but I think you want to go back from the the second controller to the first. What you are doing here is instantiating a second instance of the first controller (so you now have 3 controllers), and pushing it onto the stack. Assuming I have this correct, then if you want to move back to the first controller you should be popping the second controller off the stack, not adding a 3rd:
//mainViewController *mainviewController = [[mainViewController alloc] initWithNibName:#"mainViewController" bundle:nil];
//self.mcoreView = mainviewController;
//[mainviewController release];
// Setup the animation
[self.navigationController popViewControllerAnimated:YES];