a custom tab bar controller I am using applies the ViewController or UINavigationController like this: UIViewController* viewController = [data objectForKey:#"viewController"];
I dont knw exactly how it works but "viewController" comes out as a UINavigationController. Next, the custom tab bar controller class adds a tag like so, viewController.view.tag = THE_TAG;
Retrieving the controller is uses UIView* currentView = [self.window viewWithTag:SELECTED_VIEW_CONTROLLER_TAG];
This part is where I get confused because now when I nslog this
"currentView" I get a UILayout etc... instead of my UINavigationController. I'm assuming it applied the tag to the UIView that contained the nav controller?
How do I reference the UINavigationController within this UIView?
In the above what is THE_TAG, and can you confirm that it is unique (i.e. not zero, and not matching something being used elsewhere by the same mechanism)?
I'd be pretty wary overusing tag since there is no easy way to gaurentee globally unique tags, and when using something like self.window viewWithTag you could see just about every view in the app being checked.
It seems like you have a view and a viewController confused. A UINavigationController is a subclass of UIViewController. It is not a subclass of UIView. UIViewControllers do have a property which is a UIView class. It is probably this property that you are accessing when you use viewWithTag: . So maybe, when you use that method, you are not accessing the UINavigationController but the UINavigationController's view property (which is actually something you should probably not be messing with.)
Related
I have UITabbarMoreController which contains a few UINavigationControllers. These UINavigationControllers then contain my custom view controllers.
So the hierarchy looks something like this:
UITabbarController
- UINavigationController
-> my custom UIViewController
- ...(other children of UITabbarController look the same)
From within my custom view controller I call [self parentViewController] which should return a UINavigationController. And this really happens, I really do get a UINavigationController, BUT only when the particular UINavigationController is NOT inside moreNavigationController.
Since I have many children controllers in the tabbar controller, the tabbar controller creates a moreNavigationController. If I open a viewcontroller that is under moreNavigationController and call [self parentViewController] it returns a mysterious object with class UIMoreNavigationController
I really need to get the UINavigationController that is parent of my view controller, not the UIMoreNavigationController. Also, I tried using [self navigationController] with the same result. How can I get reference to the real closest parent of my viewcontroller? Thanks for help in advance!
In short, you can't.
Apple always try to optimise their code. One of their optimisation here is to check whether the ViewController displayed in the list of its UIMoreNavigationController is of type UINavigationController. Because UIMoreNavigationController itself is a UINavigationController it does not want to create another UINavigationController. It's trying to avoid UINavigationController nesting.
When you look at the header file of UIMoreNavigationController you will notice it has a variable
UINavigationController* _originalNavigationController; which is accualy the original UINavigationController that you created and that you want to access. Unfortunetly you cant since UIMoreNavigationController is private.
Workaround (ugly)
Pass the reference of your NavigationController to its children when you push them on it's stack.
I have a root view controller that subclasses UINavigationController. It loads in a child view with a UIButton. When that button is pressed I want to make a call from the child view's corresponding view controller (lets say ChildViewController) to the UINavigationController's pushViewController: method in the parent controller.
How is this possible without directly referencing the parent view controller? Is it achievable using a standard protocol method or do I have to create my own?
Every UIViewController has a property called navigationController. If a UIViewController is a part of a UINavigationController's stack, you can use the navigationController property in the following manner:
[self.navigationController pushViewController:yourNextViewController animated:YES];
There's no need to access the rootViewController only for pushing a new ViewController on the stack. This could get really awful if you had big navigation stacks.
By the way - Apple states that UINavigationController is not intended for subclassing. Usually, it is a good idea to listen to their warnings and directions, so you may want to revisit the subclassing approach again.
using a subclassed UIViewController which is loaded to the UINavigationController's stack may prove a better approach.
Hope this helps.
The child UIViewController that contains your child UIView and UIButton should have the parentViewController property. You can use that to get a weak reference to your UINavigationController where you can message pushViewController:animated:
I can't believe I am stuck on this but here goes.
I have a viewController which I am trying to add to another viewController via the addsubview property (basic as) however I am not doing viewController.view but viewController.myView1.
I basically have 2 root views on the xib (both with outlets) however I don't want to wire up the view property of the xib because I want to choose which view to show.
I can't get it to appear! Is the view property some sort of special hook?
I can't see why addsubview:mysubview should not work?
Some examples seem to use 2 different xib's but that seems a overkill
Firstly, Apple say a viewcontroller should be used for a whole screen full of views - (but I guess iPad container views are different).
I guess you're wanting to only use one of the viewcontrollers at once. In which case you shouldn't be using subview - just create the viewcontroller programmatically, create the view, assign the view to the viewcontroller's view property and then add the viewcontroller to the window or navigation bar.
and, in your viewcontroller:
self = [super initWithNibName:nibOne bundle:nil];
might be what you want - it allows you to use multiple nibs with a single viewcontroller.
Can you NSLog your viewController.myView1 before add it as a subview? Is it nil or not?
If it's nil, try to add this line before your addSubview: method:
[viewController view];
Note: The viewController I am talking about is the same viewController which have two root views view and myView1.
Your code should be good as this is fairly simple and I do it all the time.
Just make sure your outlets are wired properly and that you are synthesizing them and that they are public in your header.
What is up to date best solution for rotating inner views when dealing with UITabBarController? I'm playing around with a standard app view hierarchy: In my main app delegate file, I'm creating UITabBarController, then, I'm creating UINavigationController, filling it with a UITableViewController (with instantiated custom subclass), and adding that UINavigationController to the first tab bar item. Now, I need UITableViewController to autorotate. I know that I need to implement shouldAutorotateToInterfaceOrientation in all view controllers, therefore, I implemented it in my custom UITableViewController subclass implementation file:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
But the UITableViewController is not rotating :( .Now, I understand that there are UINavigationController and UITabBarController objects, that are sitting above my TVC but those two are instantiated directly not through a subclass, so there is no place where to return yes for autorotation. However, I'm able to solve this problem by subclassing a UITabBarController and implementing shouldAutorotateToInterfaceOrientation method in its implementation file. But I have read, that this is a non-recommended approach and my conscience feels bad :) Another working solution is to implement a category for UITabBarController (http://stackoverflow.com/questions/1269704/uitabbarcontroller-morenavigationcontroller-and-the-holy-grail-of-device-rotatio)...
So, these two solutions are the only ones that I was able to apply. Are there any other "out of the box" solutions, for example, setting some property on the UITabBarController or smth?
In the class which you either subclass UITableViewController or implement UITableView in UIViewController, you need to set autoresizingMask for tableView. It is something like
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
and TableView should be ok and rotated properly.
Hope this help :)
Here's what I have:
A MainWindow.xib file configured with one UIViewController (subclassed to RootViewController). This nib gets loaded at application launch.
RootViewController has two ivars, a custom subclass of UIViewController and a UINavigationController. Both of these are loaded from nibs.
When the application launches both ivars are initialized from their respective nibs, and then the UIViewController.view is added as a subview of RootViewController.view.
Inside UIViewController's view I have a control that triggers an animated swap of UIViewController and UINavigationController. This is where the problem comes in. The swap animates, but the UINavigationController's views are not properly displayed. I get a Navigation Bar with no title, and nothing else.
The UINavigationController nib and underlying functionality have been tested in a stand alone project, but there was no RootViewController.
So, my question is, can I even do this? I've successfully swapped other view controllers like this, but never a UINavigationController. I've seen some documentation that leads me to believe this might be a fools errand, but I haven't convinced myself of that yet.
Solution (Kinda):
I found a solution (workaround? hack?), but it leads to some more questions. I nixed using a Nib for the UINavigationController. Instead, I loaded my UINavigationController's rootViewController from a Nib and then created the UINavigationController programmatically with initWithRootViewController:.
NavRootViewController *navRoot = [[NavRootViewController alloc] initWithNibName:#"NavRootViewController" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:navRoot];
[navRoot release];
This works as I expect. Which leads me to the conclusion that the rootViewController property of the UINavigationController wasn't being set properly when I loaded navigationController from a Nib. And the question is, why? Should it?
Also, when you see something like this happening in one case, but not another, it can be beneficial to either create a subclass and make your nib point at that subclass, or if you already have a subclass use that.
In the subclass, override all the various init:, initWithNibName:bundle:, viewDidLoad:, viewWillAppear:, viewDidAppear: and any other appropriate methods, and in those override, just NSLog("") something about which method it is (with param values perhaps) and call the super implementation.
This will give you an observable "track" of which methods are called in which order, and you can set a breakpoint to see where that call comes from.
This will give you enough information to find missing method calls, and then you can pursue the correct problem either here, or through filing a radar or ...
In some cases, viewDidLoad and viewDidAppear or awakeFromNib may need to be called each time you add the UINavigationController back into the stack of UIViewControllers. It seems that when the typical code executes out of your AppDelegate, that the Window, or something behind the scenes is doing something special for UINavigationController that presentModalViewController doesn't do.
I think you may have missed a conceptual point.
A UINavigationController controls view controllers instead of views. It controls when and where view controllers themselves are loaded. The views themselves are loaded only as a side effect of the pushing and popping of their respective controllers.
Therefore, putting a navigation controller inside of a view controller seldom makes much sense.
If I understand what you are trying to do correctly, you should have the RootController actually set as the rootController property of the UINavigationController (yes the nomenclature is extremely confusing.) Then when your swap event occurs, you should have the navigation controller push the next view. The RootController view will disappear to replaced by the other. then you can repeat the process for an arbitrary number of view controllers.
Only in the case of a tabbar would you want a navigation controller to be a property of a view controller. Even then it should be at the top the tab's hierarchy.