Design view in Interface Builder to load lazily in UIViewController - iphone

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.

Related

Load custom UIView with Nib in ViewController

I'm making RadioPlayer with model, view and controller. Model would be a shared instance and all initialization (play, pause etc.), view is just button and slider and controller should merge view and model...
Now I've got problem how to do this especially if using nibs... Here is good example with programatically written uiview (using loadView in ViewController) .- Objective-C, Need help creating an AVAudioPlayer singleton (Wolfgangs solution) but I would like to do it with nib.
So in short - Create nib for UIView, add that view to its controller (with its model). So this would be only controller for that view (slider + play/pause) not whole view (iPhone screen).
Thanks.

iOS how to add not from source coding multiply viewsControllers to one ViewController

I'm having some problems because I don't know how it can be done. Someone help me please.
Problem:
I have a project with a UIViewController class with created all time when I create a new project in Xcode. In this viewController, I have a xib file for designing in Xcode.
What I need is to create some views and design them in Interface Builder like this:
But I need these views to be UIViewControllers, not UIViews.
The project should look like:
So I don't know how I can do this in IB but I can do it from source code in ViewController.m
tab  = [[TabBarController alloc] initWithNibName:#"mytestview" bundle:nil];
   [tab.view setFrame:CGRectMake(100, 100, 400, 600)];
   [self.view addSubview:tab.view];
But it's not my views it's a different object, and if I want to change position or size I must do it from code. How I can do same things in Interface Builder?
Let's consider following example based on Master-Detailed Application for iPhone only.
So, add new view controller in newly created project in Xcode:
I called it NewInsideViewController. Create it without xib:
Open DetailViewController.xib. Drag View Controller and View(*) objects from library to Objects area like this (I changed view's color to LightGray):
Choose this View Controller and change its Class from UIViewController to NewInsideController at the Identity Inspector:
Assign our View(*) to NewInsideController as a view:
Now all main actions in IB finished. We need to create instance of NewInsideController in our DetailViewController. You can do it by hand, but Xcode has a nice feature - drag-n-drop ;)
I called this property as myNewInsideController and DetailViewController.h looks like this:
#import <UIKit/UIKit.h>
#import "NewInsideController.h"
#interface DetailViewController : UIViewController
#property (strong, nonatomic) id detailItem;
#property (strong, nonatomic) IBOutlet NewInsideController *myNewInsideController;
#property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
Well, now our NewInsideController ready to work and manage its view. Let's add button and action to that view in order to verify this:
Write some code in IBAction in NewInsideController.
- (IBAction)insideButtonClick:(id)sender {
float rPart = arc4random()%100/100.0f;
float gPart = arc4random()%100/100.0f;
self.view.backgroundColor = [UIColor colorWithRed:rPart green:gPart blue:0.5f alpha:1.0f];
}
Run program.
If I understand the question clearly:
You have a parent view and controller, coming from a XIB.
You have placed subviews into the parent view.
You're wanting each subview placed into the parent view to have it's own (custom) controller, but you don't know how to add view controller's to your hierarchy (XCode will not let you drag view controllers into a view's canvas).
So, to answer the question succinctly: Let's assume you have a handful of custom UIViewController's in your project (each view controller consisting of a .h and a .m). Remember that you if you are laying these out in the context of the parent, they shouldn't have their own XIBs (you cannot nest XIBs in IB). What is important to note here is that you should only "layout" the interface in one location. If you want to have a XIB for each subview, this is not the correct approach. What you can (not should) do, however, is have several custom viewControllers, each connected to it's own view sitting within your parentView, and you can have the outlets of your sub view controller's set to objects in this parentView. Phew, kinda messy. The other thing you'd need to be aware of is that your parent view controller would need a reference to each of it's sub view controllers in order for you to be able to access those sub-controllers and their outlets programmatically, so for each sub view controller you add, you would also need to add an IBOutlet in your parent view controller pointing to each subviewController:
ParentViewController.h
#property (nonatomic, weak) IBOutlet CustomUIViewController *firstCustomController;
And then for example to set the background color on the view of your first custom subview/controller:
ParentViewController.m
[[[self firstCustomController] view] setBackgroundColor:[UIColor whiteColor]];
Open up your parent view controller in IB. If you look in your drawer of available objects, you'll find a generic UIViewController object. Drag this into your parent view controller (NOT onto it's views canvas, rather into the parent UIViewController object itself as seen in the left-column of IB builder). Select the generic view controller you've added and set it's class to your desired UIViewController subclass. Now, when your XIB loads, it will instantiate an instance of your custom view controller along with whatever you've added to it's canvas.
Finally, drag a generic UIView onto your canvas, placing it inside your existing controller's view (your screenshot already shows this as done). Right-click your custom view controller, and connect it's 'view' outlet to the view you added.
Now when you run, your custom view controller has a view that is on the screen that is the view of your custom controller subclass, and you didn't do any of it in code.
So now that you've done it, consider whether or not it is the best choice: Nested view controllers are messy to build (as you've seen) and aren't necessarily a good design decision: http://blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers/
Although iOS5 does support nested view controllers, personally I'd avoid using them. I value a best practice dictating one screen = one view controller.
You never, EVER, want to take views which are already under the control of a certain view controller, and make them subviews of another view controller's view.
View Controllers are the C part in the MVC design pattern - They are in charge of controlling a view (and its subviews). You can't take a view which is being managed by a controller, and stick it as a subview of a different controller's view - If you do that, it becomes ambigous who is responsible to manage this view.
Even though this "sticking" might be possible technically, it creates code which is hard to understand, hard to maintain, and most importantly - will cause bugs due to the unclarity of who is responsible to manage the view, and due to the fact that Apple's View/Controller framework doesn't support this.
For example: If the device is low on memory, Apple makes sure to unload views which are not currently displayed. Apple relies on the view controllers hierarchy to know when it can unload views. If you stick the view controller's view in another view controller's view, it's very likely that the view will never be unloaded even if it isn't visible.
Instead of breaking the view controller hierarchy, do one of the following:
Just add subviews to your view normally, either in interface builder, or in -viewDidLoad: to add them programatically, or (rarer) override -loadView.
Use view controller containment, either with Apple's ready-made ones (UINavigationController,UISplitViewController etc.) or with your own container view controllers (iOS>5).
Display view controllers modally.
The bad idea of breaking a view controller hierarchy is indeed very common and often seen in 3rd parties, probably because it's so easy and seemingly straightforward. Unfortunately this causes the aforementioned bugs :-(
I really recommend to everyone participating in this thread and comments to read Apple's View Controller Programming Guide, and watch WWDC 2011 "View Controller Containment" video.

iPhone: how to create two controller in one NIB file?

I'm a little bit lost. I have created a small app that is starting with a tab bar and in one of its view there's a button that should open a Navigation view that contains a table view.
In my NIB file I have put a Navigation Controller that contains a TableView Controller. I have created a sub-class called MyTableViewController which inherits from the UITableViewController. In the NIB I have configured the Custom Class of the TableViewController with my subclass MyTableViewController.
When the button of my App is tapped, I'm loading the NIB file with the initWithNibName but it returns me a UINavigationController.
How does it work to request the creation of MyTableViewController and get a pointer on it when I'm loading my NIB?
Thanks,
Sébastien.
This one has caught me out a few times.
When you do initWithNibName it will take the class from the custom class of the File's Owner, not the custom view of any objects .
I dont actually bother subclassing from UITableviewController any more. Just create a view controller and drag in a table view as a subview. Just make sure you hook up the data source and the delegate.
Link your TableViewController to an IBOutlet so you don't have to mess with initWithNibName.

iPhone - placing tableview within a view in another nib. Window-based

I created a window based application, and I created a separate UITableViewController file called "HomeViewController" which right now only has a basic table.
In the MainWindow.xib file, I put a UIView in the bottom half of the screen, and I wish to put the HomeViewController tableview within this newly added UIView called "conferences".
Any suggestions as to how to push this file?
First off, usually your primary first view originates from a view controller that is loaded by the UIApplication object. The MainWindow nib's owner is UIApplication so you probably don't want to be mucking with the MainWindow nib. Rather, you want to muck with the view of the view controller loaded by MainWindow nib. If you look at the view displayed in IB for MainWindow.nib, it should say which view controller's view it is loading.
So, in IB for the view of view controller being loaded by MainWindow nib, this is where you want to place your UITableView. For purposes of this explanation, I will call this view controller, MucksViewController and associated nib, MucksView.nib.
I think what I would do, then, is drag and drop a UITableView into the view for MucksView.nib. Position it in the bottom half of the screen, as you described. Attach this UITableView to an IBOutlet property in MucksViewController header file. Next, drag and drop a UIViewController object into the main window for MucksView.nib. Make this UIViewController object's owner your HomeViewController class and also attach it to an IBOutlet property of type HomeViewController in MucksViewController's header file.
Now, in MucksViewController's class file, probably in viewDidLoad method, programmatically make the HomeViewController object the data source and delegate of the UITableView object.
But, I'm wondering, do you really need HomeViewController? It would be cleaner just to make MucksViewController the data source and delegate.
I hope this helps and is not too confusing.
Instead of a UITableViewController, use a UIViewController which implements the tableview delegate and datasource. in your MainWindow.xib, add a standard uitableview as a subview to the view where it should be. then also drag a HomeViewController to the xib (which should now be a uiviewcontroller sub class). click on the tableview, open the inspecor, go to connections, and drag the delegate and datasource to the HomeViewController in the xib.

How to use 3 XIB in single class

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.