views:

97

answers:

1

Hi

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:)

+1  A: 

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.

Toastor
Thank you Toastor, this sound like what I need. I noticed in the documentation that it is an iOS 4.0 addition, will it not work on a device running 3.x? Also the documentation does not mention how you would build the NIB (dealing with outlets etc.) if a NIB view is to be wrapped. Could you point me at a resource where I could see how this functionality is implemented. Thanks again.
RickiG
I'm sorry I don't know any ressource, I figured things out myself. Within your nib, you could specify the file's owner as usual and make the appropriate connections. They will be the same for all instances, though, so you need to set tags on your new views right after instantiating to be able to distinguish between them later. As for the pre-iOS 4 replacement - I had the exact same question. I'll update my answer with a link to the question and answer right away.
Toastor
I went down the loadNibNamed path, as you state in ther question,not to abandon 3.x users. I am starting to feel a bit stupid, I can find no reference to how I should build my XIB, should my XIB view have a "Class" in IB, what is file owner if I load it at runtime? Where to do the IBOltlet/IBAction belong when doing it like this. Apple does it like this in their taggedLocation:[[NSBundle mainBundle] loadNibNamed:@"EventTableViewCell" owner:self options:nil]; they don't assign it to an array, they just type out the line above and it works? Thank you again for trying, I am completely lost now:)
RickiG
You do it like you would for any nib. Say you have a viewcontroller and add the contents of the nib to the VC's view. The VC has a method `-(IBAction)buttonPressed: (id)sender;`. If in your nib you add a button and set the files owner to your VC subclass, you can connect the action to the button as usual. The action method will be called when tapping ANY instance of that button however, that's why you need tags if you instantiate the nib more then just once. Otherwise you wouldn't know which button has been tapped.
Toastor
As for the array-thing: When instantiating a nib, there may be more then one top-level view, which is why the return value is an array. You don't need to assign it, but you need to access its content to get a reference to the view that the nib contains...
Toastor
Ok, finally I got it running, the problem, with both me understanding it and the code running correctly, was that I should not connect the view in the XIB with files owner. This results in my custom view not being added to the controllers view, but instead becomes the controllers view. I see now that I can gather releated view in the same NIB file and load them according to index. Thank you for helping out Toastor:)
RickiG
You're welcome - glad it works now :)
Toastor