I'm trying to create a custom UIView which holds references to its own IBOutlets. I then want to put this custom UIView into another nib.
I'm doing some additional logic in the custom UIView's awakeFromNib
method. Unfortunately, when I try to access the IBOutlets
in awakeFromNib
, they are nil.
Here's the setup:
- I have a
UIView
subclass,CustomView
. - I have a custom
.xib
file with three subviews - In the other nib (that belongs to the view controller), I have dragged a
UIView
onto the view, and then changed the custom class toCustomView
. - I tried setting the view in the
CustomView
nib in IB to a custom classCustomView
and connecting theIBOutlets
to the view, but they were still nil. - I tried setting file owner to
CustomView
and connecting theIBOutlets
to file's owner, but they were still nil. - I also tried using another
IBOutlet UIView *view
and then adding that as a subview toself
inawakeFromNib
but that also didn't do anything.
Here's the code:
// CustomView.h
@interface CustomView : UIView
@property (nonatomic, retain) IBOutlet UITextField *textField;
@property (nonatomic, retain) IBOutlet UIView *subview1;
@property (nonatomic, retain) IBOutlet UIView *subview2;
// CustomView.m
@implementation CustomView
@synthesize textField, subview1, subview2;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self setup];
}
- (void)setup {
// Fails because self.textField is nil
self.textField.text = @"foo";
}
As in Dr. Acula's answer, This is probably because custom view's nib is lazy loaded when loaded from another nib (Nested nib loading), so we need to instantiate it manually. In swift code will look like this :
I ended up using the steps in the most recent edit here and they worked beautifully.
You use a plain
UIView
as the top level view in thexib
.You then set file's owner to the custom subclass (
CustomView
).Finally, you add a line:
in the
if (self != nil)
block in bothinitWithCoder
andinitWithFrame
.Voila! The
IBOutlets
are hooked up and ready to go after the call. Really pleased with the solution, but it was very difficult to dig up.Hope this helps anyone else.
EDIT: I updated the link to one that isn't dead. Since I never spelled out the full code, here is what it looks like after modification:
This pattern has become so common that I actually created a category on
UIView
calledUIView+Nib
, which implements the following method:So the above code can be simplified to:
Note also that the above code can be refactored even more, since the logic is exactly the same in
initWithFrame:
andinitWithCoder:
. Hope that helps!I am assuming the XIBs' structure is something like this
If this is right, then your CustomView will be created but as it is not read from CustomView.xib it doesn't have any IBOutlets assigned.
However, if your CustomViewController.xib looks like following
then this should work. The IBOutlet of CustomView instance should be set by the CustomViewController.xib.
Better than setting any IBOutlets in the CustomViewController.xib would be to implement awakeAfterUsingCoder: in your CustomView and create a replacement object by loading your CustomView.xib in there. This way your CustomView remains truly custom and you don't have to edit other XIBs to change the structure, add/remove IBOutlets, etc.