I have a class and want to handle 3 Xib or nib (I don't know the exact difference) files from it I know that 3 files can be handled from 3 different view controller but can it be done from single view controller?
I tried this on a button click, but with no success
-(IBAction)goToNext2{
[self initWithNibName:#"SecondNib" bundle:nil];
[self presentModalViewController:self animated:YES];
}
Can it be done with a navigation controller?
Don't send -init... twice to the same object, ever. Use NSBundle's loadNibNamed:owner:options: instead to load other nibs. Anyway, I suspect your view controller already has a view set up. What do you load from the other nib? If you need to present another view as modal, you should have another view controller object for that. Asking a view controller to present itself as a modal view controller doesn't make sense. It can present another view controller, though.
EDIT: -presentModalViewController:animated: tells one view controller to show another view controller modally. The opposite operation, -dismissModalViewControllerAnimated:, tells the first vc to dismiss the modal vc it has presented previously. This approach requires two distinct view controller objects (they may be of the same class, though).
If you don't need a whole new view controller to display a certain view, you can use NSBundle's loadNibNamed:owner:options: to load a view and then add it as a subview to another view. More often than not, you set up a view in Interface Builder, set the File Owner's class to the class of your view controller and connect the necessary outlets of the view controller. Now, the important part. When the nib loads, the outlets are assigned actual objects unarchived from the nib. If your view controller has a "main" nib (where its view outlet is connected) and a "secondary" nib which you load by sending [[NSBundle mainBundle] loadNibNamed:#"MySubview" owner:self options:nil], you must not connect the same view outlet in the secondary nib. Make other outlets (relevant only for the secondary nib) and connect only them, otherwise really bad things will happen.
I encourage you to thoughtfully read about the NSBundle method, NIBs in detail and
modal view controllers. They may appear to be boring basics stuff, but they're very important to understand and use correctly.
Related
I'm just trying to make the most basic tab bar controller that gets presented modally. I want to use nibs, as opposed to doing it all programatically, but I really don't understand Interface Builder:
Why can't I drag a tab bar controller into my veiw?
Why does IB create another "window" when I drag a TBC to the document window?
Why are there 2 view thingys in the same nib?
Why do I get this message (crash) when I try to present the modal view: "nib but the view outlet was not set" ?
How do you remember which little connections you need to make in IB, other than the obvious ones you reference in the code?
Is there an IB tutorial out there that goes beyond just the most basic pre-made application templates and actually explains what's going on?
Why can't I drag a tab bar controller into my view?
Because only other views can be dragged onto views. A view controller is not a view.
Why does IB create another "window" when I drag a TBC to the document window?
Because every view controller has its own main view. If you double click a view controller in IB, its view opens.
If you really want to create all controllers from a NIB file, do it like this:
Create a fresh empty XIB file called "TabBarController.xib". It contains nothing but the entries for File's Owner and First Responder.
Drag a UITabBarController into this XIB. Ignore the view that gets opened (you can close it).
Configure the tab bar controller according to your needs, especially by dragging as many UIViewController objects (or UIViewController subclasses) onto the tab bar controller as you have tabs. If these child view controllers should be instances of your custom view controller subclasses, make sure to set their classes accordingly in the Inspector.
For each child controller of the tab bar, create another XIB file in Xcode, this time using the View XIB preset. Let's call these "ChildController1.xib", ... Open all of them in IB and set their File's Owner class to the class of the corresponding child controller (i.e., UIViewController or a subclass). Then connect the views in these XIB to the view outlet of File's Owner. Configure these views as you need them (by adding the actual UI elements of the child views and possibly connecting other outlets if necessary).
Close the child XIBs and return to TabBarController.xib. For each child controller, open the Attributes Inspector and set its NIB Name attribute to "ChildController1", "ChildController2", ... Then close the XIB.
In your code:
NSArray *nibFile = [[NSBundle mainBundle] loadNibNamed:#"TabBarController" owner:self options:nil];
UITabBarController *tabBarController = [nibFile objectAtIndex:0];
[self presentModalViewController:tabBarController animated:YES];
I broke down and just configured the TabBarController without using Interface Builder. The more I'm getting into iPhone development, the more I'm realizing that IB is bad, and to not use it except for the rare components with absolute layouts. In this case, all you would gain by using it would be the icons and titles on each tab. IB doesn't really provide any earth-shattering visualization on that.
I really wish nibs rendered down into some readable text format, so you could always drop to the code to understand what was going on, but that's not the case, so I'll gladly add 6 lines of code to make my program not crash
I'm getting confused on view controllers and would love a straight example. Here's the preamble:
I have a UIViewController with a matching .xib.
By default IB gives me a single View in the Document window.
I can make it appear by telling my UIWindow to addSubview:controller.view and bringSubviewToFront:controller.view
Here's the questions:
Should I add another View to the ViewController in IB? Or is there a better, programmatical way?
How do I tell the ViewController to switch between the Views?
From the ViewController downward, what does the code look like to achieve this?
I'm trying things but just making a mess so I thought I'd stop and ask...
Note that every button, label, image, etc. in your main view controller is actually a view in itself, however I've interpreted your question to mean that you want to manage multiple full-screen views or "screens". Each screen should have its own view controller to manage it. So to get the terminology right, a view-controller is an object that manages a single full-screen view (or almost full screen if it's nested inside a navigation controller or tab bar controller for example) and a view is the big area managed by the view controller as well as all the sub-views (images, buttons, labels, etc.) within it (they are all UIView sub-classes). The view controller manages all of them on that screen, if you want another screen/page then you should create a new view controller to manage it.
The root view controller (the one you add to the window) can be a plain old normal view controller that you've designed in IB, however it's probably more useful if you use a navigation controller or a tab bar controller and add your designed view controller to that - then you can push additional view controllers as needed.
Another way (if you don't want navigation or tab-bar style) would be to transition to other view controllers directly in the main window using whatever transitions you like (or just replace the old one). We'll leave that for now though.
Any sub-views of your main view controller (the one you've designed in IB) will be automatically loaded from the nib file, but you can also add your own views programatically if you want (typically you would use one or the other, i.e. nibs or programatically, but you can mix and match if you want). To do it programatically, override loadView in the view controller and then call [super loadView]; then do [self.view addSubView:myOtherView]; (create the myOtherView first of course). Note that the first time .view is accessed on your view controller, it actually calls loadView to create the view, so inside loadView it's important to call [super loadView]; before trying to access self.view :D
To switch between views, using the navigation or tab bar controllers makes it very easy. So put your main view controller inside (for example) a navigation controller and put the navigation controller in the window, so you've got window->navigationController->myController. Then from an action method in your view controller (you can hook up the action methods in IB), for example when an "about" button is pressed do this:
- (void)doAbout
{
// Create the about view controller
AboutViewController* aboutVC = [AboutViewController new];
// Push the view controller onto the navigation stack
[self.navigationController pushViewController:aboutVC animated:YES];
[aboutVC release];
}
Note that the about view controller is created programatically here - if your about view is designed in IB then instead use initWithNibName:bundle: to create it.
And that's how you manage multiple screens.
Ola Folks,
In an iPhone application I am displaying different views by using the addSubView:SomeViewController.view method.
I want to be able to, at the very least, log the view controllers that are in the view hierarchy that is being displayed. I would prefer to be able to get a handle to a specific view controller.
I know how to iterate the views, I just do not see how to access the view controllers of those views. I am looking for something that will give me the type of access to the view controllers that UINavigationController::ViewControllers does.
I thought I could get away with:
for (UIViewController* oVC in [self.view subviews])
but this is not having the intended effect.
If someone has a way of doing this, please share it with me.
-isdi-
A view doesn't keep a reference to its view controller (or know anything about view controllers in general), so you'll have to keep track of that mapping yourself. If you keep all of your view controllers in an array viewControllers, you could do something like:
- (UIViewController *) viewControllerForView:(UIView *)view {
for (UIViewController *viewController in viewControllers)
if (viewController.view == view)
return viewController;
return nil;
}
The standard way for a view to interact with the view controller that owns it is by having the view controller set as the delegate or action target of the view. The view is designed not to have any details about the delegate or action target.
If you have implemented your own view, just add a member to hold a reference to the view controller. Or adopt a delegate model for the view so that it does not matter what class the delegate is.
If you are treating the views as a stack and want to maintain a stack of view controllers along side it, similar to what UINavigationController does for you, you must do so manually. Couple every call of addSubview:viewController.view with a call to [myViewControllerArray addObject:viewController] and remove the viewController form the array when the view is removed from the view hierarchy.
I am sure this is an easy question, but one that has escaped me for some time now.
Say I have a UIViewController, either defined as a root in an XIB or on a stack. At some point in my code I want to replace it with another view controller. Just flat out replace it. How would I do that?
I have tried defining the controller and assigning, but not sure what actually makes it push on the screen with the absence of a navigation controller.
I think when you say that you want to replace the view controller, what you actually mean is that you want to replace the view. Bear in mind that view controllers aren't visible, but every view controller maps to a view, which can become visible by getting added as a subview of a visible view.
Your solution of replacing self.view with the new view controller's view may work in your particular case, but it's probably not the "correct" answer to your question. There are going to be cases where this solution won't work for you.
Let's say you have a simple view based application with no navigation controller and no tab bar controller. In your app delegate you construct an instance of YourFirstViewController, and you call [window addSubview:yourFirstController];. Your view hierarchy now consists of a UIWindow with a single subview -- the view for YourFirstViewController.
Now let's say the user presses a button on that view, which is handled by an IBAction defined in YourFirstViewController. You want to respond by "replacing" YourFirstViewController's view with a view associated with YourSecondViewController. I put "replacing" in quotes because we more commonly present a view by pushing its view controller onto a navigation stack, or calling presentModalViewController:animated: to present the view modally, but let's assume that you've rejected those options for some reason, and you actually do want to manually replace YourFirstViewController's view with YourSecondViewController's view.
This is a simple matter of manipulating the view hierarchy. You want to remove YourFirstViewController's view from its superview (the UIWindow in this case), and you want to add YourSecondViewController's view as a subview to replace it. Your action would therefore look something like this:
- (IBAction)replaceButtonClicked {
UIView *mySuperview = self.view.superview;
YourSecondViewController *secondController = [[YourSecondViewController alloc] init];
[mySuperview addSubview:secondController.view];
[self.view removeFromSuperview];
[secondController release];
}
When we use a methods like -pushViewController:animated: or -presentModalViewController, the receiving controller manipulates the view hierarchy for us. This may make it seem like we're looking at view controllers on the screen, but we're not. We're just looking at a big hierarchy of nested views going all the way up to a UIWindow at the top.
You can present a new view controller modally:
[self presentModalViewController:aViewController animated:YES];
This won't outright replace the current VC, but it will display a new view over the current view.
I've managed to get my myself confused... I've got a fairly complex View Controller much of which is developed programatically. I'd like to pop up a "dialog" on top of the view controller at some point and I'd like to "design" that view in Interface Builder because it's fairly straightforward (background UIImageView, some UILabels and a UIButton).
I've created the .xib and am now subclassing UIView with the IBOutlets,etc. I'm now trying to wire it up and realizing I probably need to add an initWithNibName: method so this will instantiate correctly...then I realize that I'm really just making another UIViewController and I don't think we're supposed to have UIViewController views w/in other UIViewController views?!?
So now I'm re-thinking how to go about this "correctly." How best to use IB to design a simple 1/4 screen view that will pop up over a main view?
Call +[NSBundle loadNibNamed:owner:] to load the NIB file that contains your view. If you specify your view controller (i.e., self) as the owner, any connections you make to File's Owner in the NIB file will then be made to the view controller. So you could declare an outlet to your custom view in the view controller and after the call
[NSBundle loadNibNamed:#"MyView" owner:self];
the outlet variable will point to the view object. Alternatively, you can use -[NSBundle loadNibNamed:owner:options:], which returns an array of the top-level objects in the NIB.