How are *.xib, *.m and *.h files related? - iphone

How/where in the code does the nib file get related to its *.m and *.h files?
Specifically I'm talking about when you create a new Objective-C class, not using the initWithNibName method.
Wherever this relationship is defined is obviously used by the 'Files Owner' relationship in Interface Builder. I imagine it's a *.plist file somewhere or something.

NIB files describe classes instances.
When you drag and drop a component in a NIB with Interface Builder, actually, you create an instance.
If you drag and drop a UIViewController for instance, and if you did define a subclass of UIViewController in your OWN classes with a .m and a .h, you'll be able to say to interface builder : "use my custom subclass of UIViewController for this object instance".
This is achieved in interface builder with Tools/Identity Inspector and then Class identity : at this place, you can put your own classes that indirectly refer to your own .h and .m

NIB files describe interface. They're produced from XIB files. XIB files are text (XML, to be precise), NIBs are binary. You typically edit XIB files in Interface Builder, and they get compiled into NIBs as the project is built.
.h files contain class interfaces. Interface Builder uses those to compile a list of Objective C classes in your app, and to produce the list of outlets and actions they provide. When you design a XIB, you typically provide one of your ViewController classes as the file owner. Interface Builder would scan a .h file and produce the outlet/action list from it.
.m files contain code. They're not used by the Interface Builder directly. But they can and often do contain code that loads those NIB files. And, of course, they contain code of action handlers.

Although the question is marked as answered, I don't really see the answer that was asked for...
Usually the code itself specifies the relation when creating a view controller, like so:
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
That tells the system to create the view controller instance, and look for "MyView.xib" to load and wire to MyViewController - MyViewController would also have been set to file's owner in the XIB.
Now another way to relate your view controller and the xib, is that in some cases you are actually creating view controller instances in a xib. The tab bar controller is a great example, where for a tab you specify a view controller instance to create, along with the nib name that it will use.
Note this means you can have several xib files that make use of a single view controller, if you want the same controller to with with different kinds of screens. You don't end up doing that often but it can be powerful, when used correctly (it can also be a mess if you try to make one view controller that does too many things).

Related

How to connect outlet with xib object from code?

What happens when we connect the xib objects with class outlets? How to do such connection from code without wiring them in interface builder?
IBOutlets are just instance variables or properties that get set by the nib loading machinery when the nib is loaded at runtime. There's nothing particularly special about them. The trick in setting them up programmatically is finding the object(s) in the nib that you want to connect. If you load the nib using -[NSBundle loadNibNamed:owner:options:] you get an NSArray back containing all the top level objects in the nib (i.e. the objects at the top of the hierarchy in the Document Outline Inspector in IB). You can iterate through these and their subviews to find the objects you want to hook up IBOutlets. Take a look at the Loading Nib Files Programmatically section of the Resource Programming Guide.

run time change of custom class in xib

I would like to change at run time the custom class as defined in a xib identity inspector.
This is to avoid to define lots of xib and view controller.
I've not found anything related to that subject.
Define a MyCustomUIViewController that would inherit from UIViewController. And set that controller as the file's owner of your XIB. This controller will have to support the defualt XIB IBOutlet and IBActions.
Then make other controllers (MyCustomUIViewControllerForThis, MyCustomUIViewControllerForThat, ...) inherit from MyCustomUIViewController
Then when you load it, that should give something like :
MyCustomUIViewControllerForThat* controller = [[MyCustomUIViewControllerForThat] alloc] initWithNibName:#"YourNib" bundle:nil];
This way, you can define in your XIB wanted Outlets and actions, and customize them if wanted in your MyCustomUIViewControllerForThat class.

UIView build in Interface Builder connected to my custom UIViewController

I was trying to use IB in a slightly different way that I am use to and I can't get it working extending the normal approach I use, when dealing with IB.
Instead of making a new UIViewController and have the view XIB generated for me and everything linked together by Xcode, I would like to just build a small (320x40px) View XIB and link it to my already existing ViewController.
I start out by making a new file in Xcode, select "view XIB".
I then open IB and add some labels etc. to the view and I set "Files Owner" to be my existing ViewController.
In my existing ViewController I set the IBOutlets for the labels etc. I put in my view.
I go back to IB and hook up the UILabels to my outlets in "Files Owner".
I would now think that I have a reference to the labels inside the XIB, in my viewController.
This is not really the approach I would like, I see no need for my viewController to have a reference to labels inside my view.
How I usually do in code:
My ViewController controls a bunch of UIViews made entirely in code and who instantiate them by:
UIView *customView = [[CustomView alloc] initWithFrame:aFrame];
[customView setTag:MY_CUSTOM_VIEW];
[customView setDelegate:self];
[self.view addSubView:customView];
[customView release];
After this I would access the labels, buttons etc. from my controller by using the [(UILabel*)[[self.view viewWithTag:MY_CUSTOM_VIEW] myLabel] setText#"Hello, World"];
have my UIViewController implement what ever methods the customView protocol required.
How to get that functionality with IB
Should I first build a MyCustomView class extending the UIView class, have it hold all my IBOutlets, set MyCustomClass as files owner and then instantiate that as shown above?
Is it OK to have a view act as viewController for the IB view and how would I relay actions to my "real" viewController?
What I would like to achieve is to deal with instantiating and laying out several UIViews in my UIViewControllers code, but have the freedom of designing some of these UIViews in IB.
All the info I can find is regarding the standard "build a UIViewController with a XIB for the view" or "How to build libraries of IB components".
I hope it makes sense and thanks for any help given:)
You can create whatever view structure you want in Interface Builder and then instantiate it using the UINib class. Once you create an UINib object it loads the contents from the nib and keeps them. Then, whenever you send it the instantiateWithOwner:options: message, it will instantiate the objects contained in the xib and return an array with the top level views. You can then add these views to your view hierarchy and handle them just like any other view you created programmatically.
If you keep the UINib object (as a property for example), you can instantiate the contents again and again, which allows your xib to be used like a template.
update: For a pre-iOS 4 workaround see my recent question and answer.

What are the conventions for declaring a UITabBarController in mainwindow.xib?

I have a mainwindow.xib file with a UITabBarController as the base view controller of the app. So inside the UITabBarController I've added about 10 sub UIViewController objects as tabs. Most of them are just a UITableViewController subclass or a UINavigationController containing a UITableViewController subclass.
In this design, each UIViewController is fully loaded on app startup, including calling the viewDidLoad method of each view controller. Is there any way to get around that? Since the view controllers are just UITableViewControllers with no other outlets, it seems excessive to create a NIB for each tab (which I assume would allow the viewDidLoad to only get called when the user first switches to the tab? Or am I wrong on that?)
Anyway, my question mainly, is: how is it conventionally done? If you have 10 different view controllers on one UITabBarController, do you put them all in mainwindow.xib? If so, should each have its own NIB, and if not, where do you put them, and how do you add them to the tab bar?
What you want to do is to define the UIViewController views in a different xib file for each view - the reason they all get instantiated is that when the xib loads, all objects held in the xib load - and that means all your views and view controllers since you have defined them there.
In MainWindow.xib where you have the tab bar defined, you can still set within each tab the view controller type that will be called and also the XIB file to use for that type (create a new project with the "TabBar application" template and the second default view will be like this).
Then as you press tabs the view controllers will be instantiated from the different XIB files you have defined.
Note that this means if you are using IB to add buttons to the navigation bar, you have to do that back in the TabBar xib and not in the xib you use to define the view. You can still link actions to the view controller definition within the tab.
The way Apple suggests doing it for pure NIB files is how you say: Each sub-view in its own NIB file.
Instead of doing this, I would create the UITabBarController programmatically. That way you can define all your simple views in code, and still load complex views from NIB files.
Personally, I prefer creating as many of my views programatically as possible. The compiled code has a smaller footprint than the NIB files and I feel like I have more control. I mostly use Interface Builder to mock up applications.

How to keep controllers out of xib

As a newbie, IB and all the possible connections is bewildering to me. Most tutorials I've found are what I'd call the reincarnation of spaghetti code, in which the entanglement is all the connections created by dragging. Of course, I want to use IB for layout of views (sizing & placing visual elements), that's what IB is great for. But a controller is not a view, so it's less confusing if all my controllers are solely code and don't appear anywhere in IB. I suspect this will minimize the spaghetti. It also encourages the one-xib-per-view admonishment. To that end, and here's the question, where can I find example projects that adhere to this strategy?
I don't have a set of sample projects, but I will give you some information about how things work and when you should create controller's in a XIB file or in code.
If your controllers are created dynamically by way of a user's action, you typically won't instantiate them in a XIB file. Instead, you'll instantiate them in code like harms mentions above. Once you do that, you'll still need a mechanism to connect this controller that was created in code, to the user interface elements that you've created in IB.
The mechanism that IB provides for solving this is the File's Owner. Mastering the File's Owner is essential to "getting" Interface Builder.
The file's owner is not an object that is "in" the XIB file, it's an object that's represented in the XIB file. It's a placeholder for an object that will already exist when the XIB file is loaded. When NIB files are loaded at run time, they're loaded with the NSBundle method -[NSBundle loadNibNamed:ownwer:options:]. The owner parameter is used to resolve the file's owner placeholder object in the XIB/NIB file. When the file is loaded at runtime, all of the connections made against the file's owner will resolve against the object you passed in as the owner parameter to the NSBundle method. On the iPhone, you typically don't load NIB file yourself. Instead UIViewController does it for you. The default implementation of UIViewController's loadView method might look something like this:
- (void)loadView {
[[self nibBundle] loadNibNamed:[self nibName] owner:self options:nil];
}
So, by connecting the elements in your XIB file to the file's owner, you'll be connecting them to your view controller.
You will have some controllers that are statically in your application - they'll be alive forever. A navigation or tab controller along with their root items are typically alive for for the entire life of their application. When that's the case, I'd set those view controllers up in the MainWindow.xib file. Most of the other controllers would be created dynamically, and programatically in response the the user doing things.
Good question. The pattern I try to stick with is making the controller in code, adding IBOutlets and IBActions for the things in the XIB/NIB that interact with that code, and a thing in the controller's constructor which loads the XIB/NIB with "self" as the owner, and in IB I connect stuff to the "File's Owner" placeholder, whose identity I will have specified to be the my controller's class.