How to load a UIView using a nib file created with Interface Builder
There is also an easier way to access the view instead of dealing with the nib as an array.
1) Create a custom View subclass with any outlets that you want to have access to later. --MyView
2) in the UIViewController that you want to load and handle the nib, create an IBOutlet property that will hold the loaded nib's view, for instance
in MyViewController (a UIViewController subclass)
@property (nonatomic, retain) IBOutlet UIView *myViewFromNib;
(dont forget to synthesize it and release it in your .m file)
3) open your nib (we'll call it 'myViewNib.xib') in IB, set you file's Owner to MyViewController
4) now connect your file's Owner outlet myViewFromNib to the main view in the nib.
5) Now in MyViewController, write the following line:
[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];
Now as soon as you do that, calling your property "self.myViewFromNib" will give you access to the view from your nib!
Thank you all. I did find a way to do what I wanted.
- Create your
UIView
with theIBOutlet
s you need. - Create the xib in IB, design it to you liking and link it like this: The File's Owner is of class
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). - Connect your controls with the
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:NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView" owner:self options:nil]; QPickOneView* myView = [ nibViews objectAtIndex: 1]; myView.question = question;
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.
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"):
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"Blah"
owner:self options:nil];
Blah *blah;
for (id object in bundle) {
if ([object isKindOfClass:[Blah class]]) {
blah = (Blah *)object;
break;
}
}
assert(blah != nil && "blah can't be nil");
[self.view addSubview: blah];
}
This supposes you have a UIView
subclass called Blah
, a nib called Blah
which contains a UIView
which has its class set to Blah
.
Category: NSObject+LoadFromNib
#import "NSObject+LoadFromNib.h"
@implementation NSObject (LoadFromNib)
+ (id)loadFromNib:(NSString *)name classToLoad:(Class)classToLoad {
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
for (id object in bundle) {
if ([object isKindOfClass:classToLoad]) {
return object;
}
}
return nil;
}
@end
Swift Extension
extension UIView {
class func loadFromNib<T>(withName nibName: String) -> T? {
let nib = UINib.init(nibName: nibName, bundle: nil)
let nibObjects = nib.instantiate(withOwner: nil, options: nil)
for object in nibObjects {
if let result = object as? T {
return result
}
}
return nil
}
}
And an example in use:
class SomeView: UIView {
class func loadFromNib() -> SomeView? {
return self.loadFromNib(withName: "SomeView")
}
}
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:
NSArray *bundleObjects; MyView *currView; NSMutableArray *myViews = [NSMutableArray arrayWithCapacity:myWrapperViews.count]; for (UIView *currWrapperView in myWrapperViews) { bundleObjects = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil]; for (id object in bundleObjects) { if ([object isKindOfClass:[MyView class]]){ currView = (MyView *)object; break; } } [currView.myLabel setText:@"myText"]; [currView.myButton setTitle:@"myTitle" forState:UIControlStateNormal]; //... [currWrapperView addSubview:currView]; [myViews addObject:currView]; } //self.myViews = myViews; if need to access them later..
I would use UINib to instantiate a custom UIView to be reused
UINib *customNib = [UINib nibWithNibName:@"MyCustomView" bundle:nil];
MyCustomViewClass *customView = [[customNib instantiateWithOwner:self options:nil] objectAtIndex:0];
[self.view addSubview:customView];
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.