Loading a UIView subclass from NIB size issues

Ron Srebro picture Ron Srebro · Jul 28, 2010 · Viewed 8.1k times · Source

I have a subclass of UIView that needs to calculates it's height according to it's width. When created in code everything works. However when I try to create the view in Interface builder, and although I override all related methods, I can't get the size of the view set in interface builder.

- (id)initWithCoder:(NSCoder *)aDecoder
{
    NSLog(@"init with coder before super width %d",super.frame.size.width); // returns 0
    self = [super initWithCoder:aDecoder];
    NSLog(@"init with coder after super width %d",super.frame.size.width); // still returns 0
}

- (void) awakeFromNib
{
      NSLog(@"width of view %d",super.frame.size.width); // Returns 0 as well
}

- (void) setFrame:(CGRect)aFrame
{
    [super setFrame:aFrame]; // Called from initWithCoder by super. Correct frame size. 
}  

So my next guess was the maybe the superview of my view is setting my view's frame after awakeFromNib. Well it turns out it doesnt. I overrided setFrame on my view, and it is called during initWithCoder.

So this is what I know so far:

  1. First initWithCoder is called
  2. During initWithCoder a call to setFrame:(CGRect)aFrame is sent
  3. in setFrame the size of the frame is correct, and I call [super setFrame:aFrame]
  4. awakeFromNib is called
  5. super.frame.size.width = 0 in awakeFromNib self.frame.size.width is also 0
  6. When the process is done, it seems that the view is a few pixels below where it's suppose to be, but I guess my code get so massed up with the dimensions that it might be something I do.

Any help will be appreciated

Answer

TJez picture TJez · Apr 29, 2011

If you extend initWithCoder, be sure to call the super method. It is during this super call that setFrame will be called on your class.

You can then re-use your standard initWithFrame call.

I always do the following:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder]; // Required. setFrame will be called during this method.
    return [self initWithFrame:[self frame]];
}