In iOS, why can a UIView (and others) be only embedded in a UINavigationController or UITabBarController? What's special about these two classes?
Edit: oops, wanted to ask 'UIViewController' instead of UIView.
No, its not true. UIView is embedded with UIViewController. This class provides life cycle for UIView. It takes responsibility from initializing the view to deallocating the view.
UINavigationController and UITabBarController are just derived from UIViewController. They provide extra functionality for building hierarchy and switching between hierarchy respectively.
UIView can be embedded in any ViewController or its subclass. UINavigationController and UITabbarController are nothing but subclasses of UIViewController.
I think the embedding you're referring to is the embed in menu item which only allows for UITabBarController and UINavigationController. This means that XCode will take your UIViewController subclass and embed it in one of these two controllers. They are special because they are controllers of other controllers (collections of UIViewControllers). Xcode is simply taking some of the pain out of building a view controller and then adding it to a navigation controller or a tab bar. You can easily embed it in one of these with one click and no code. Much easier than in past versions of XCode.
If you're talking about "embed" as in Interface Builder, yes, as of iOS 5, Interface Builder only gracefully designs user interfaces for three view controller containers, UINavigationController, UITabbarController, and UISplitViewController. These are the three container controllers that come out of the box. You can, though, do your own view controller containment. See Session 102 in WWDC 2011 for information on view controller containment. Also refer to the section on view controller containment in the UIViewController Class Reference.
Related
I would like to subclass UIViewController with multiple nibs.
For example:
BaseViewController has a nib with a label, and is subclassed from UIViewController
SecondViewController has a nib with a button, and is subclassed from BaseViewController.
SecondViewController should also have the label from the BaseViewController.
I have searched an not found any tutorials on this, only tutorials with ways to add UIView's to UIViewControllers, so I'm not sure this is even possible.
Can anyone explain how to do this, or point me in the direction to the resources that show how to do this (or if it's even possible at all)?
I am using a hierarchy of controllers and it works just fine. As long as your correct match nibs to properties at each level, there is no reason you cannot define parent controllers in a hierarchy.
I don't think that what you are asking can be done. A view can be loaded from only one nib. You could have the base view controller set up with a nib, and descendant view controllers do additional setup in viewDidLoad.
So my app's core is a tab bar. In each of 3 tabs is a UINavigationController subclass. Each one has a different type of table in it, which when a row is tapped, a detail is shown etc.
I currently have a 3 separate subclasses of UINavigationController, one for each tab. Then when a new tab is pressed, the table's controller is pushed.
I just read that you're not supposed to subclass UINavigationController. I'm not overriding any of UINavigation Controller's functionality, but I am overriding it's UIViewController functionality in viewDidLoad. Honestly that's just about it. It seems pretty silly, but Im unclear on how to get the Navigation Controller functionality without subclassing the way I have.
So how am i supposed to have a UINavigationController that I don't subclass? What is the approach that you're supposed to take to switch out the views when a tab is selected?
I'm pretty much a noob. Will Apple reject my app for subcalssing UINavigationController if im only overriding viewdidload?
I've heard folks say not to subclass UINavigationController, and instead 'present it modally.' I have used modal presentation a little bit, but I honestly dont' quite get how it would apply...
Thanks for your help!
What are you doing in viewDidLoad? What about do it in root view controller, not in navigation controller?
P.S. I think Apple will not reject your app for subclassing UINavigationController.
You should use categories to add extra functionality like that. It would look something like this:
#implementation UINavigationController (CustomViewDidLoad)
- (void)viewDidLoad
{
//code goes here
}
#end
You can add this to the bottom of the file that initializes the navigationcontroller
More info about categories (at the bottom): http://cocoadevcentral.com/d/learn_objectivec/
I have a uiview class and i want to switch to other uiview class but without using addsubview
is there any other way to do that except the one (addSubView)
If you have UIViewControllers for the corresponding UIViews, and have a UINavigationController to handle your view flow, you can use pushViewController message at the mentioned navigation controller.
Since you have a navigation controller you can use pushViewController:animated to add anotherViewController to the navigation stack. You can also use presentModalViewController:animated. The section on Navigation Controllers in View Controller Programming Guide explains this very well.
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.
I just realised that my 'root' viewController should have been a UINavigationController. Now I want to change this to be a UINavigationController instead and just curious what my best option would be. I built this view and all other views using IB if that makes a different.
I'm mostly worried that I would have to do a lot of copy/pasting and recoding to get everything right or will be it be as easy as manually editing my controller and change the extension to UINavigationController.
Thanks
You do not convert an existing view controller into a navigation controller.
Even though UINavigationController is a subclass of UIViewController, it's task is the management of other view controllers, not the management of views themselves. You don't swap them out one for the other. Instead, you set UIViewControllers to be controlled by the nav.
To add a nav to a project in IB, open the xib and drag over a UINavigationController. Then set the navigation controller's rootControlller property to the existing UIViewController.
And you're done.
You can also "Embed" the Navigation Controller by selecting the View Controller in IB then select Editor->Embed In->Navigation Controller
You can instantiate a trivial not-subclassed UINavigationController and give it your original UIViewController as its root controller, like:
YourRootViewController *rootViewController = [[YourRootViewController] initHoweverYouInitIt];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
and maybe an [rootViewController release];, depending on how you are going to manage memory.
UINavigationController has an 'is-a' relationship with UIViewController, so you should be able to change its class type in Interface Builder with no additional changes.