run time change of custom class in xib - iphone

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.

Related

iphone+same xib for different class

I have two class and in both class tableview uses custom nib file(for table cell)as well as i make IBOutlet instance of myview controller to that custom cell nib file but i can not use same nib for both class becuase i have give file owner of that xib to the myviewcontroller so when i used that one in another class it give error so any ideas so use the same xib for both the view controller?
If you want to reuse your custom table cell with multiple view controllers, check out this answer. The two methods described there let you load your custom table cell from a nib file without having to set the File's Owner to your specific controller.

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.

How to get a reference to a control in the view?

If I have a UIScrollView set up in the view via the Interface Builder, how do I get a reference to it in the ViewController implementation? I want to programmatically add labels to the scroll view.
For example, in C# if you have a textbox declared in the UI/form, you can access it by simply using the ID declared for that textbox. It doesn't seem this simple in objective c.
Thanks
Kevin
Assuming I understand you rightly and you are instantiating a view controller from a .xib containing subviews including the UIScrollView you want, there are two ways - first, you can find it in the subviews array that is owned by the view controller. Second, you can add an IBOutlet reference to it in your header file, then in interface builder make the connection using the connections inspector. Then you can refer to the object in your code, change frame, add labels etc.
You need to wire your ViewController up to your Nib files. This is pretty straightforward. This is your basic workflow for using Interface Builder on the iPhone/iPad:
Set the Class of the 'File's Owner' to the class of your view controller. You can do this by selecting the 'File's Owner' object in your nib window, pressing Command-4, and setting the class via the drop-down.
Create properties in your View Controller with the following format:
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
The IBOutlet keyword is a macro that evaluates to nothing. So it doesn't actually do anything to your code, it just exists to let Interface Builder know that the 'scrollView' property can be bound to.
Control-drag from the object you'd like to bind to your ViewController. In the popup you can select the property you'd like to bind to the scroll view object.
This sort of stuff is pretty basic Xcode stuff. If you read any tutorial out there it'll cover this. Good luck, and enjoy!
edit:
I should add that if you used the default "New UIViewController Subclass" from the New File dialog, it will have done step one for you. You'll have a nib file and a View Controller that already know about each other.
Yes, the code you wrote is all you need in your header. Just make sure you connect the Scroll View object to the property in Interface Builder.
Yup! 'viewDidLoad' is added after all the connections specified in the Nib file have been made, so you can be confident that scrollView point to the correct object (assuming everything in the Nib is wired correctly, which is an easy mistake to make)

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.

UINavigationController NIB requires File's Owner to have a view?

I'm having a problem setting a View Controller nib's default View Outlet in Interface Builder. Here's my setup:
I have a TabBar based application where I load a Navigation Controller as a modal view...
MyNavCtrlrSubClass *menu = [[MyNavCtrlrSubClass alloc]initWithNibName:#"MenuController" bundle:nil];
[tabBarController presentModalViewController:menu animated:anim];
MenuController itself is structured as follows:
MenuController.xib
File's Owner (MyNavCtrlrSubClass : UIViewController)
Navigation Controller (UINavigationController)
Navigation Bar (UINavigationBar)
Root View Controller (Nib Name is set to load AnotherViewController.nib)
Navigation Item -> (UINavigationItem)
This all works fine, except that when MyNavCtrlrSubClass is loaded, I get the following error:
Loaded the "MenuController" nib but the view outlet was not set
It's clear why this is happening - File's Owner doesn't have an outlet connection for its view. The question is what should I set as its view, and does something have to be set in the first place? The Navigation Bar is the only candidate in MenuController.xib, but doing this will just size the UINavigationBar itself to the fullscreen mode, so to speak.
I'm obviously missing something in IB, but what? MyNavCtrlrSubClass.m has no code itself, except an IBOutlet for the UINavigationController. Am I making a mistake trying to set this up entirely in IB? The idea is to keep the modal Navigation Controller in one nib, and all the views it loads in separate nibs, but since MenuController is just a container for the navigation and contains no views itself, I'm obviously designing it wrong. :)
If you're wondering why I'm not designing it some other way, it's because I'm trying to obey my (possibly mistaken) perception of how IB asks you to build an ideal hierarchy.
Any help would be greatly appreciated.
I think you might not be understanding how the File's Owner is meant to be used in a NIB file. I've written up a response describing the file's owner under another question.
When you invoke this line:
[[MyNavCtrlrSubClass alloc] initWithNibName:#"MenuController" bundle:nil]
You create an instance of MyNavCtrlrSubClass, and tell it to load #"MenuController". Then in the MenuController.xib file, there is a second unrelated UINavigationController with things inside of it. When MenuController.nib is loaded at runtime, that second navigation controller will be created.
A second problem is that telling a UINavigationController to load a NIB file isn't really sensible because navigation controllers create and manage their own views. You really want to create the root view controller, and tell that view controller to load a NIB file.
Try this:
MyRootViewController *rootController = [[[MyRootViewController alloc] initWithNibName:#"AnotherViewController" bundle:nil] autorelease];
MyNavCtrlrSubClass *menu = [[MyNavCtrlrSubClass alloc] initWithRootViewController:rootController];
Where your XIB File looks like this:
File's Owner (Class set to MyRootViewController, view outlet connected to subsequent UIView)
UIView
Subview A
Subview B
After you're confortable with how all of this is working, you might also consider instantiating the navigation controller and root view controller in one XIB file like you were starting to do in the code you posted.
The crux of this question is stated by Travis himself: "How would you load Navigation Controller nib, designing as much as possible in Interface Builder?" And also from the example, it looks like this means the UINavigationController and associated UIViewControllers.
With this interpretation, the answer is you cannot fully configure a UINavigationController and it's UIViewControllers in a single XIB. Yes it is intuitive to want to do this so you are not crazy.
When I say you cannot do this, I mean the most commonly used framework methods do not have a way to handle this. There is no [UINavigationController alloc] initWithMegaNibName. Yes you could stuff almost anything in a single XIB and write code to hydrate objects in special ways, but I don't think that's what you're looking for.
You could use two or more XIBs as Jon suggested, but then things are less self contained and so you have many folks who find it simpler to do part, or all, of the controllers in code.
Unfortunately there is not a 1:1 correspondance between Interface Builder capability and code like there is on other dev platforms. I generally prefer to be able let designers participate as much as possible in creating assets, but most of them I know do not code objective-c.
In IB, in the MenuController nib add a UIView and set that view as the outlet. You will need to set that view for a UIViewController. Here is a quick link to an Apple page showing a basic setup. Not sure if it will help you at your current stage though.