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.
I too wanted to do something similar, this is what I found: (SDK 3.1.3)
I have a view controller A (itself owned by a Nav controller) which loads VC B on a button press:
In AViewController.m
Now VC B has its interface from Bnib, but when a button is pressed, I want to go to an 'edit mode' which has a separate UI from a different nib, but I don't want a new VC for the edit mode, I want the new nib to be associated with my existing B VC.
So, in BViewController.m (in button press method)
Then on another button press (to exit edit mode):
and I'm back to my original Bnib.
This works fine, but note my EditMode.nib has only 1 top level obj in it, a UIView obj. It doesn't matter whether the File's Owner in this nib is set as BViewController or the default NSObject, BUT make sure the View Outlet in the File's Owner is NOT set to anything. If it is, then I get a exc_bad_access crash and xcode proceeds to load 6677 stack frames showing an internal UIView method repeatedly called... so looks like an infinite loop. (The View Outlet IS set in my original Bnib however)
Hope this helps.
I found this blog posting by Aaron Hillegass (author, instructor, Cocoa ninja) to be very enlightening. Even if you don't adopt his modified approach to loading NIB files through a designated initializer you will probably at least get a better understanding of the process that's going on. I've been using this method lately to great success!
@AVeryDev
6) To attach the loaded view to your view controller's view:
Presumably, it is necessary to remove it from the view to avoid memory leaks.
To clarify: the view controller has several IBOutlets, some of which are connected to items in the original nib file (as usual), and some are connected to items in the loaded nib. Both nib's have the same owner class. The loaded view overlays the original one.
Hint: set the opacity of the main view in the loaded nib to zero, then it won't obscure the items from the original nib.
Shortest version:
You should not be setting the class of your view controller to be a subclass of
UIView
in Interface Builder. That is most definitely at least part of your problem. Leave that as eitherUIViewController
, some subclass of it, or some other custom class you have.As for loading only a view from a xib, I was under the assumption that you had to have some sort of view controller (even if it doesn't extend
UIViewController
, which may be too heavyweight for your needs) set as the File's Owner in Interface Builder if you want to use it to define your interface. I did a little research to confirm this as well. This is because otherwise there would be no way to access any of the interface elements in theUIView
, nor would there be a way to have your own methods in code be triggered by events.If you use a
UIViewController
as your File's Owner for your views, you can just useinitWithNibName:bundle:
to load it and get the view controller object back. In IB, make sure you set theview
outlet to the view with your interface in the xib. If you use some other type of object as your File's Owner, you'll need to useNSBundle
'sloadNibNamed:owner:options:
method to load the nib, passing an instance of File's Owner to the method. All its properties will be set properly according to the outlets you define in IB.Here's a way to do it in Swift (currently writing Swift 2.0 in XCode 7 beta 5).
From your
UIView
subclass that you set as "Custom Class" in the Interface Builder create a method like this (my subclass is called RecordingFooterView):Then you can just call it like this:
let recordingFooterView = RecordingFooterView.loadFromNib()