The Problem with Interface Builder

Most iOS developers seem to have a love-hate relationship with Interface Builder: they will either use Interface Builder for everything or completely avoid it and do everything in code.

Example

Let’s take a look at a simple example where using Interface Builder can be painful. I’m going to create a simple view in Interface Builder and then animate an image in the view.

Interface Builder

When I tap the button I want to animate the image of the monkey moving down. This is all very simple.

- (IBAction)animate:(UIButton *)sender
{
    [UIView animateWithDuration:0.3f animations:^{
        self.monkeyImage.center = CGPointMake(self.monkeyImage.center.x, self.monkeyImage.center.y + 188);
    }];
}

And it all works as expected.

Animated Monkey

Now let’s say once the monkey is down at the bottom of the screen we want to add another image – a zebra. Again, the code is very simple.

- (IBAction)animate:(UIButton *)sender
{
    [UIView animateWithDuration:0.3f animations:^{
        self.monkeyImage.center = CGPointMake(self.monkeyImage.center.x, self.monkeyImage.center.y + 188);
    } completion:^(BOOL finished) {
        UIImageView *zebra = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"zebra"]];
        zebra.frame = CGRectMake(0, 300, 128, 120);
        [self.view addSubview:zebra];
    }];
}

Animated Monkey and Zebra

Uh-oh, what happened? Why did adding a new image cause our monkey to reset to it’s original position? Turns out every time layoutSubviews gets called Interface Builder will reset the position of all views. Adding a new image to the view is simply one of the triggers that causes layoutSubviews to be called.

So how do we fix this problem? It’s pretty easy – we just need to add the monkey image in code instead of through Interface Builder. If you are animating a view it’s usually better to create the view in code.

So when should we use Interface Builder?

Does this mean we should completely avoid Interface Builder? Not necessarily. In my opinion Interface Builder can still be useful for building many views, even when you’re doing animations. For example, if I wanted a custom background image in this example it would be very simple to add it in Interface Builder. Interface Builder is still great at allowing us to visually create the screen without having the burden of any code maintenance.

I would avoid using Interface Builder either if it causes layout issues (like in this example) or if you’re trying to do visual inheritance. If you have multiple views with similar elements there is no straightforward way of doing visual inheritance and you usually end up duplicating quite a bit of functionality. It’s obviously pretty easy to copy-paste between views in Interface Builder, but it’s also far from ideal.

You can find my example on GitHub. Happy coding.