iPhone Dev - Where is RootViewController instantiated in a Navigation-based application? - iphone

I can't seem to find where it's actually instantiated. I looked in the myProjAppDelegate.m and saw this:
self.window.rootViewController = self.navigationController;
But it says that the window's rootViewController property is really just a UIViewController, not a UITableViewController, which is what the RootViewController.m class is a subclass of. I wrote a custom method in my RootViewController.m and tried to call it on self.navigationController in myProjAppDelegate.m and got a SIGABRT, so it seems like this is not it. Can anyone help me out?

It's not visible in code. Your MainWindow.xib contains a Window and a Navigation Controller which are connected via outlets to your AppDelegate.
Both the Window and the Navigation Controller get instantiated when the application loads the .xib files.
Inside the Window (in the MainWindow.xib) is a RootViewController, that is the RootViewController you are talking about.
Regarding the class, UITableViewController inherits from UIViewController.

Related

No call to shouldAutorotateToInterfaceOrientation when using custom TabBarController

I have created a custom TabBarController that inherits from UIViewController (NOT UITabBarController because it is not intended for subclassing). Everything works fine except the orientation support.
My TabBarController is set as the rootViewController on my UIWindow and contains an internal array of UIViewControllers. In my case I have added UINavigationControllers as the root of each tab.
When pushing a new UIViewController to any of my UINavigationControllers in my TabBarController I get a call to shouldAutorotateToInterfaceOrientation, this is all fine because here I can set which UIViewController should support which orientation (as described in the Apple documentation).
However when I go back by pressing the back button in my UINavigationBar I do not get a call to shouldAutorotateToInterfaceOrientation hence the view we display will end up in the wrong orientation.
I have done a quick test by replacing my custom TabBarController with a UITabBarController and I get the call to shouldAutorotateToInterfaceOrientation when pressing the back button so there must be something wrong here but I cannot figure out what.
Why don't I get the calls to shouldAutorotateToInterfaceOrientation? Is the UITabBarController doing something I have missed?
Has anybody here experienced the same problem? Do you have any ideas that might be worth trying because I have run out of ideas.
EDIT
This issue is resolved by adding each UIViewController within the TabBarController as a child using the iOS5 container view controller.
Add the UIViewController as a child with this method: addChildViewController Then override automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers and return YES.
Now you should get the shouldAutorotateToInterfaceOrientation callbacks in your UIViewControllers
I have seen such problems before, and it always boiled down to adding the -shouldAutorotateToInterfaceOrientation: method to all view controllers, not just the topmost one as you might expect.
(and if you're lazy, just add a category to UIViewController)

Combining TabBar and Navigation Controllers Question

In my appDelagate I have a UIViewController called "FrontPage" which is basically a log in screen. Once the login has authenticated it removes itself from the superview and creates a tabbarcontroller, navigationcontroller (inside tabbar), and various UIViewControllers in the NC and on their own in the tab bar. I then push my TabBarVC.view to the windows subView.
It works but I was hoping after I set the windows subview to TabBarVC.view I could release the TabBarViewController to dealloc it and the appdelagate would own the TabBarVC, but when I do it's crashing.
As I'm typing this I'm realizing I never pass the actual TabBarVC, just the view but is there a way to do this?
Also if I completely FUBAR'd this up let me know.
You should set the window's rootViewController property to your UITabBarController instance similar to this:
// set the tab bar controller as our root view controller
[self.window setRootViewController:tabBarController];
To clarify, this will add the TabBarController, its view and all of its subviews to the window's view hierarchy for you and I would recommend you use this method for your login view controller as well.
You could make your UITabBarController an IBOutlet to the app delegate (or just keep the code you have that generates it). Make it a retained property of the app delegate, synthesize the property, and either create the UITabBarController in the app delegate (self.tabBarController = ...) or if you use an xib make the IBOutlet connection from the UITabBarController to the app delegate in the xib.
You could add the UITabBarController to the app's window, and then add the FrontPage UIViewController on top of it. Once you remove the FrontPage from the window, the UITabBarController will already be present underneath it.

Adding a Navigation Controller to an existing project

I'm sure this is something stupid (it nearly always is when I finally decide to post :) but I can't seem to figure it out, so here goes:
I have a project which contains a UITableViewController (among others) which works fine, but I decided I wanted to enable editing on it and that means it needs to be contained within a UINavigationController. So I added one to the project, set it up so the view is loaded from my table view controller nib, and... it comes up empty. Just a white view with the blue nav controller bar up top.
I've verified that the table view is getting loaded - viewDidLoad runs, at least. Clearly something's not hooked up, probably something in IB, but I just can't seem to see it.
Any suggestions?
In your AppDelegate.h class
UINavigationController *navigationController;
In your AppDelegate.m class
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
navigationController = [[UINavigationController alloc]
initWithRootViewController:viewController];
[self.window addSubview:navigationController.view];
}
Try this. It may solve your problem.
Change the class inheritance from UITableViewController to uiviewcontroller. In the xib put the table view and attach it with an iboutlet for uitableview, set the two required protocols for table view and hope that is done if I am not missing anything.
It seems you forget to pass nib name in the interface builder. Try selecting viewControler inside UINavigation Controller in interface builder and set the nib name and class there. If you by-mistake set the nib name and class name on UINavigation controller remove the nib name and class from there.
Its to use the navigation bar rather than using navigation controller since it can fulfill your requirements.
Just place the navigation bar in Xib file & add an action button event over the button.

Why doesn't the SplitView iPhone template have a nib file for the RootView?

I'm diving into iPad development and am learning a lot quickly, but everywhere I look, I have questions. After creating a new SplitView app in Xcode using the template, it generates the AppDelegate class, RootViewController class, and DetailViewController class. Along with that, it creates a .xib files for MainWinow.xib and DetailView.xib.
How do these five files work together?
Why is there a nib file for the DetailView, but not the RootView?
When I double click on the MainWindow.xib file, Interface Builder launches without a "View" window, why?
Below is the code for didFinishLaunchingWithOptions method inside the AppDelegate class. Why are we adding the splitViewController as a subview?
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after app launch
rootViewController.managedObjectContext = self.managedObjectContext;
// Add the split view controller's view to the window and display.
[window addSubview:splitViewController.view];
[window makeKeyAndVisible];
return YES;
}
Thanks so much in advance for all your help! I still have a lot to learn, so I apologize if this question is absurd in any way. I'm going to continue researching these questions right now!
MainWinow.xib is the default window created by every Cocoa touch project. It's the window all other windows are added to, usually in the AppDelegate.
AppDelegate, I'm assuming you know already. This is your base class for your Application.
SplitViewController is an UISplitViewController and it is added to MainWindow.xib for you using IB, but not added to the Window in MainView.xib until didFinishLaunchingWithOptions: is run.
By default SplitViewController manages two ViewControllers as a convenience for you. Typically these are a UITableView (called RootViewController in the template), and a UIViewController (called DetailViewController). Although you can remove these entirely if you want.
RootViewController is simply a UITableViewController. It is added to SplitViewController in IB.
DetailViewController is a UIViewController, and it is also added to IB in MainWindow.xib for you.
Why is there a nib file for the
DetailView, but not the RootView?
I believe DetailView is loaded from a nib file to facilitate memory management. But it just as easily could have been created programmatically. There is not a nib for the RootView because it is already added and initialized in UISplitViewController. It could have just as easily been loaded from a xib file.
When I double click on the
MainWindow.xib file, Interface Builder
launches without a "View" window, why?
This default iPad template uses a UISplitViewController called SplitViewController and not a UIView Called View as other iPhone templates.
Below is the code for
didFinishLaunchingWithOptions method
inside the AppDelegate class. Why are
we adding the splitViewController as a
subview?
SplitViewController only exists in the MainWindow.xib, it's not added to Window (in MainWindow.xib). So it is added here. If it were nested in SplitViewController there would be no need to added in the AppDelegate.
This is the document you want to read

How should I manage swapping a UINavigationController in and out of another UIViewController?

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.