I'm trying to do something a bit elaborate, but something that should be possible. So here is a challenge for all you experts out there (this forum is a pack of a lot of you guys :) ).
I'm creating a Questionnaire "component", which I want to load on a NavigationContoller
(my QuestionManagerViewController
). The "component" is an "empty" UIViewController
, which can load different views depending on the question that needs to be answered.
The way I'm doing it is:
- Create Question1View object as a
UIView
subclass, defining someIBOutlets
. - Create (using Interface Builder) the
Question1View.xib
(HERE IS WHERE MY PROBLEM PROBABLY IS). I set both theUIViewController
and theUIView
to be of class Question1View. - I link the outlets with the view's component (using IB).
I override the
initWithNib
of myQuestionManagerViewController
to look like this:- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) { // Custom initialization } return self; }
When I run the code, I'm getting this error:
2009-05-14 15:05:37.152 iMobiDines[17148:20b] *** Terminating app due to uncaught exception '
NSInternalInconsistencyException
', reason: '-[UIViewController _loadViewFromNibNamed:bundle:]
loaded the "Question1View" nib but the view outlet was not set.'
I'm sure there is a way to load the view using the nib file, without needing to create a viewController class.
Thank you all. I did find a way to do what I wanted.
UIView
with theIBOutlet
s you need.UIViewController
(No custom subclass, but the "real" one). The File Owner's view is connected to the main view and its class is declared as the one from step 1).IBOutlet
s.The
DynamicViewController
can run its logic to decide what view/xib to load. Once its made the decission, in theloadView
method put something like this:That's it!
The main bundle's
loadNibNamed
method will take care of initializing the view and creating the connections.Now the ViewController can display a view or another depending on the data in memory, and the "parent" screen doesn't need to bother with this logic.
For all those that need to manage more than one instance of the custom view, that is an Outlet Collection, I merged and customized the @Gonso, @AVeryDev and @Olie answers in this way:
Create a custom
MyView : UIView
and set it as "Custom Class" of the rootUIView
in the desired XIB;Create all outlets you need in
MyView
(do it now because after point 3 the IB will propose you to connect outlets to theUIViewController
and not to the custom view as we want);Set your
UIViewController
as "File's Owner" of the custom view XIB;In the
UIViewController
add a newUIViews
for each instance ofMyView
you want, and connect them toUIViewController
creating an Outlet Collection: these views will act as "wrapper" views for the custom view instances;Finally, in the
viewDidLoad
of yourUIViewController
add the following lines:This is a great question (+1) and the answers were almost helpful ;) Sorry guys, but I had a heck of a time slogging through this, though both Gonso & AVeryDev gave good hints. Hopefully, this answer will help others.
MyVC
is the view controller holding all this stuff.MySubview
is the view that we want to load from a xibMySubView
that is the right size & shape & positioned where you want it.In MyVC.h, have
In MyVC.m,
@synthesize mySubView;
and don't forget to release it indealloc
.UIView *view
(may be unnecessary, but worked for me.) Synthesize & release it in .mMySubview
, and link the view property to your view.IBOutlet
's as desiredBack in MyVC.m, have
The tricky bit for me was: the hints in the other answers loaded my view from the xib, but did NOT replace the view in MyVC (duh!) -- I had to swap that out on my own.
Also, to get access to
mySubview
's methods, theview
property in the .xib file must be set toMySubview
. Otherwise, it comes back as a plain-oldUIView
.If there's a way to load
mySubview
directly from its own xib, that'd rock, but this got me where I needed to be.I have a convention of naming xibs with views in them the same as the view. Same as one would do for a view controller. Then, I don't have to write out class names in code. I load a UIView from a nib file with the same name.
Example for a class called MyView.
In your code, create a new MyView like this:
MyView *myView = [MyView nib_viewFromNibWithOwner:owner];
Here's the category for this:
I'd then wire up buttons with actions from the controller I am using, and set things on labels using the outlets in my custom view subclass.
I would use UINib to instantiate a custom UIView to be reused
Files needed in this case are MyCustomView.xib, MyCustomViewClass.h and MyCustomViewClass.m Note that
[UINib instantiateWithOwner]
returns an array, so you should use the element which reflects the UIView you want to re-use. In this case it's the first element.I'm not sure what some of the answers are talking about, but I need to put this answer here for when I search in Google next time. Keywords: "How to load a UIView from a nib" or "How to load a UIView from an NSBundle."
Here's the code almost 100% straight up from the Apress Beginning iPhone 3 book (page 247, "Using The New Table View Cell"):
This supposes you have a
UIView
subclass calledBlah
, a nib calledBlah
which contains aUIView
which has its class set toBlah
.Category: NSObject+LoadFromNib
Swift Extension
And an example in use: