Loading custom UIView from nib, all subviews contained in nib are nil?

strahlr picture strahlr · Sep 28, 2011 · Viewed 39.1k times · Source

I have a custom UIView object with a nib that defines the view/subview layout. My outlets are connected, and when I init the object from initWithFrame: everything is in order.

The problem I'm having is when I'm using IB to embed the UIView into another nib; the custom UIView appears, but none of the subviews it contains appear - in fact their symbols all resolve to nil. I have a very minimal initWithCoder: and awakeFromNib: implementation (just does logging) and my understanding is that as the nib is deserialized the subviews should at least be initialized during the process?

The only conclusion I'm coming to on my own is that one of two things is happening: either my outlet references are corrupt/bad and aren't working, or my understanding of load-from-nib process is faulty and I'm missing something.

Thanks in advance!

Edit: (Code posted for Nekto as requested... as you'll see, it does logging and thats it, heh.)

- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) {
        NSLog(@"ThumbnailGridView.initWithCoder frame= %f, %f", self.frame.size.width, self.frame.size.height);
    }
    return self;
}

- (void)awakeFromNib
{
    NSLog(@"ThumbnailGridView:awakeFromNib");
}

Edit 2: Nibs, controllers, subviews, etc.

Nibs: I have a single nib containing a UIView. This UIView contains a single UIScrollView, which is filled with a grid of UIViews that are defined in another nib. (Note: this part works fine, as the fill is done programmatically and works with an initWithFrame: call.) The problem here is that the UIScrollView symbol is nil after initWithCoder: and awakeFromNib: are both called, so objects are just being added to nil and nothing happens. If the scrollview symbol was not nil, I'm sure this would work.

Controllers: There are two controllers that utilize this, one is done with initWithFrame: and works perfectly, the other embeds it as a nib-based reference. (As mentioned elsewhere here, defining a UIView in IB, setting the custom class.) I stepped through the code, and that view -is- being initialized properly - only its subviews are "missing".

Does this help give a clearer picture of the situation at all?

Answer

Robin Summerhill picture Robin Summerhill · Sep 28, 2011

You may be misunderstanding how nib loading works. If you define a custom UIView and create a nib file to lay out its subviews you can't just add a UIView to another nib file, change the class name in IB to your custom class and expect the nib loading system to figure it out. You need to modify initWithCoder of your custom UIView class to programmatically load the nib that defines its subview layout. e.g.:

- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        [self addSubview:self.toplevelSubView];
    }
    return self;
}

Your custom view's nib file needs to have the 'File's owner' class set to your custom view class and you need to have an outlet in your custom class called 'toplevelSubView' connected to a view in your custom view nib file that is acting as a container for all the subviews. Add additional outlets to your view class and connect up the subviews to 'File's owner' (your custom UIView).

Alternatively, just create your custom view programmatically and bypass IB.