Interface Builder é um editor visual de interfaces integrado ao Xcode para desenvolvimento iOS e macOS. Permite criar UI através de arrastar e soltar, configurar Auto Layout e conectar código via IBOutlet e IBAction. Vamos analisar como o IB funciona, as diferenças entre Storyboard e XIB, e por que o @IBDesignable é necessário.
Principais pontos
Interface Builder é um componente do Xcode projetado para o design visual de interfaces de usuário. A história do IB começou em 1988 na NeXT, muito antes do surgimento do iOS. Stefan Pope desenvolveu a primeira versão para o NeXTSTEP — o sistema operacional que se tornou a base do macOS e iOS. Em 1996, a Apple adquiriu a NeXT e integrou o Interface Builder ao Xcode.
No Xcode moderno, o Interface Builder suporta três formatos de arquivo: Storyboard, XIB (Xcode Interface Builder) e arquivos XIB para células de tabela e visualizações personalizadas. Cada um desses formatos armazena uma descrição XML da hierarquia de elementos da UI, suas propriedades, restrições e conexões com o código.
O IB funciona ao nível do UIKit: botões, rótulos, campos de texto, tabelas, coleções e restrições são arrastados com o mouse para a tela. O Xcode compila arquivos .storyboard e .xib em arquivos nib (Interface Builder compilado) durante a compilação, o que reduz o tamanho do pacote e acelera o carregamento.
Segundo a Apple, mais de 70% dos projetos iOS em UIKit usam o Interface Builder em diferentes estágios de desenvolvimento. Apesar do crescimento do SwiftUI, o IB continua sendo o padrão para aplicações comerciais que suportam iOS 12 e versões anteriores, bem como para interfaces personalizadas complexas que exigem configuração detalhada do Auto Layout.
Antes do Xcode 4, o Interface Builder era um aplicativo separado executado paralelamente ao editor de código. No Xcode 4 (2011), a Apple fundiu o IB e o editor de código em um único IDE. Isso permitiu alternar entre código e layout sem trocar de janela e ver alterações de propriedades em tempo real através do painel Attributes Inspector.
| Versão do Xcode | Ano | Mudanças no Interface Builder |
|---|---|---|
| Xcode 3 | 2008 | IB — aplicativo separado, suporte iOS 2.0 |
| Xcode 4 | 2011 | IB integrado ao IDE, surgimento do Storyboard |
| Xcode 5 | 2013 | Auto Layout com menu de restrições, pré-visualização de telas |
| Xcode 6 | 2014 | Size Classes, @IBDesignable, Preview Assistant |
| Xcode 11 | 2019 | SwiftUI Canvas, IB permanece para UIKit |
| Xcode 15 | 2023 | SwiftUI Preview como ferramenta principal, modo legado do IB |
Com a introdução do SwiftUI em 2019, a Apple mudou o foco para o desenvolvimento declarativo, no entanto o Interface Builder permanece integrado ao Xcode para suportar projetos UIKit. Milhares de aplicações existentes continuam a usar o IB, e a Apple não anunciou sua remoção.
O Interface Builder suporta dois formatos principais: Storyboard (.storyboard) e XIB (.xib). A diferença entre eles está no escopo e no caso de uso.
Storyboard é um arquivo que contém toda a cena da aplicação: várias telas (UIViewController), transições entre elas (segues), controladores de navegação, barras de guias e todos os elementos da UI. Um Storyboard é carregado uma vez na inicialização a partir do Info.plist através da chave UIMainStoryboardFile (k). Isso é conveniente para visualizar o fluxo de telas, mas cria problemas com conflitos de merge no git, já que a descrição XML de toda a aplicação é armazenada em um único arquivo.
XIB (significa Xcode Interface Builder) é um arquivo para um único componente: uma UIView individual, UITableViewCell, UICollectionViewCell ou um ViewController. O XIB é carregado sob demanda através de UINib(nibName:bundle:) (k) ou do método Bundle.loadNibNamed (k). Arquivos XIB são mais fáceis de mesclar, mais compactos e carregam mais rápido, pois não contêm a descrição de toda a aplicação.
| Critério | Storyboard | XIB |
|---|---|---|
| Escopo | Várias telas + transições | Uma tela ou componente |
| Segues | Suporta (push, modal, unwind) | Não suporta |
| Merge no git | Difícil (um XML grande) | Simples (muitos arquivos pequenos) |
| Carregamento | Ao iniciar a aplicação | Sob demanda (preguiçoso) |
| Reutilização | Apenas através de referências de storyboard | Alta (células, cabeçalhos, visualizações) |
| Recomendação da Apple | Não recomendado para projetos grandes | Recomendado para componentes |
Desde o Xcode 11, a Apple recomenda usar XIB para componentes individuais e evitar Storyboards monolíticos. Para navegação entre telas, prefere-se a navegação baseada em código através de UIStoryboardSegue (k) manualmente ou coordenadores.
Arquivos .storyboard e .xib armazenam XML no formato Interface Builder Cocoa Touch XIB (dt). Exemplo de uma estrutura simplificada:
<!-- XIB file with UIView and UILabel -->
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB"
version="3.0">
<objects>
<view id="abc-123"
userLabel="CustomHeaderView"
contentMode="scaleToFill">
<subviews>
<label id="def-456"
text="Title"
textColor="darkTextColor"
fontDescription="title1"/>
</subviews>
</view>
</objects>
</document>Cada elemento tem um id (an) único, pelo qual o IB liga o nó XML ao objeto em tempo de execução. Durante a compilação, o Xcode converte o XML em formato nib binário (.nib), reduzindo o tamanho do arquivo em aproximadamente 40%.
Auto Layout é um sistema para posicionar elementos na tela através de relações matemáticas (restrições). O Interface Builder fornece uma interface visual para criar, editar e depurar restrições sem escrever código. Cada restrição descreve uma dependência: view.leading = superview.leading + 16 (k) ou view.width = 2 * otherView.height (k).
No IB, as restrições são criadas através do menu Pin (fixar margens, largura, altura) e do menu Align (centralizar, bordas, linha de base). O painel Size Inspector mostra todas as restrições do elemento selecionado, suas prioridades (required/high/low) e permite editar multiplicadores e constantes.
O IB também suporta UIStackView — um contêiner que gerencia automaticamente o layout das visualizações filhas. Basta colocar elementos em uma pilha na tela, e o IB gerará as restrições necessárias automaticamente. Isso acelera significativamente o layout em comparação com a colocação manual de restrições.
Size Classes são uma abstração que agrupa dispositivos por largura e altura da tela: Compact e Regular. As combinações (wC hR para iPhone retrato, wR hR para iPad) permitem especificar diferentes restrições e layouts de elementos para diferentes cenários. No Interface Builder, alternar entre size classes altera o conjunto de restrições ativas na tela.
| Dispositivo | Orientação | Width Class | Height Class |
|---|---|---|---|
| iPhone (exceto Max/Plus) | Retrato | Compact | Regular |
| iPhone (exceto Max/Plus) | Paisagem | Compact | Compact |
| iPhone Plus/Max | Paisagem | Regular | Compact |
| iPad | Qualquer | Regular | Regular |
| iPad Split View | 1/3 da tela | Compact | Regular |
Exemplo de uma restrição com variação de size class:
import UIKit
class AdaptiveViewController: UIViewController {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var leadingConstraint: NSLayoutConstraint!
private func updateConstraints() {
let isRegular = traitCollection.horizontalSizeClass == .regular
leadingConstraint.constant = isRegular ? 40 : 16
titleLabel.font = isRegular
? UIFont.preferredFont(forTextStyle: .largeTitle)
: UIFont.preferredFont(forTextStyle: .title1)
}
override func traitCollectionDidChange(
_ previousTraitCollection: UITraitCollection?
) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass {
updateConstraints()
}
}
}No código acima, traitCollectionDidChange reage à alteração de size class, atualizando a restrição e a fonte. O Interface Builder permite definir valores padrão para cada size class através do inspetor, enquanto o código é usado para cenários dinâmicos que não podem ser descritos estaticamente.
A conexão entre a interface visual no Interface Builder e o código Swift/Objective-C é feita através de dois mecanismos: IBOutlet (Interface Builder Outlet) e IBAction (Interface Builder Action). Ambos são criados arrastando com a tecla Ctrl pressionada da tela do IB para o arquivo do controlador.
IBOutlet é uma anotação que declara uma referência a um elemento da UI. O Xcode a conecta automaticamente ao objeto correspondente no arquivo nib ao carregar. Se a conexão for quebrada (por exemplo, um elemento for renomeado), a aplicação falha com um erro NSUnknownKeyException (k). IBOutlet é marcado como weak (k), já que o nib possui o objeto e o controlador é apenas um observador.
IBAction é um método chamado em um evento de elemento da UI: pressionar botão, alterar texto, alternar interruptor. O IB conecta UIControlEvent (k) ao método através de addTarget:action:forControlEvents: (k). No código, IBAction parece um método normal com tipo de retorno IBAction (dt).
import UIKit
final class LoginViewController: UIViewController {
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var loginButton: UIButton!
@IBOutlet weak var spinner: UIActivityIndicatorView!
@IBAction private func loginButtonTapped(_ sender: UIButton) {
guard let email = emailTextField.text, !email.isEmpty,
let password = passwordTextField.text, !password.isEmpty
else {
showAlert(message: "Fill in all fields")
return
}
loginButton.isEnabled = false
spinner.startAnimating()
performLogin(email: email, password: password)
}
private func performLogin(email: String, password: String) {
/// API call via URLSession
let request = LoginRequest(email: email, password: password)
APIClient.shared.login(request) { [weak self] result in
DispatchQueue.main.async {
guard let self else { return }
self.spinner.stopAnimating()
self.loginButton.isEnabled = true
switch result {
case .success:
self.navigateToMainScreen()
case .failure(let error):
self.showAlert(message: error.localizedDescription)
}
}
}
}
private func showAlert(message: String) {
let alert = UIAlertController(
title: "Error",
message: message,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}O exemplo mostra uma configuração padrão: IBOutlet para campos de texto, botão e spinner, IBAction para lidar com o toque. Todas essas conexões são definidas no Interface Builder através de Ctrl+arrastar. Se a conexão não estiver configurada, o IBOutlet será nil (v) em tempo de execução, causando uma falha no acesso — por isso o IBOutlet é declarado como weak var (k s) com desembrulho implícito.
@IBDesignable é uma anotação Swift que permite exibir uma UIView personalizada diretamente na tela do Interface Builder em tempo real. O desenvolvedor vê as alterações de código sem executar a aplicação. @IBInspectable é uma anotação para propriedades, adicionando-as ao painel Attributes Inspector do IB, onde os valores podem ser alterados interativamente.
Essas anotações são especialmente úteis ao criar bibliotecas de componentes de UI: botões personalizados, campos de entrada com máscara, indicadores animados. O IBDesignable usa prepareForInterfaceBuilder() (fn) para compilação separada do código de construção, sem afetar o binário principal da aplicação.
import UIKit
@IBDesignable
final class GradientButton: UIButton {
@IBInspectable var startColor: UIColor = .systemBlue {
didSet { updateGradient() }
}
@IBInspectable var endColor: UIColor = .systemPurple {
didSet { updateGradient() }
}
@IBInspectable var cornerRadius: CGFloat = 12 {
didSet {
layer.cornerRadius = cornerRadius
layer.masksToBounds = true
}
}
private let gradientLayer = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame: frame)
setupGradient()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupGradient()
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
}
private func setupGradient() {
layer.insertSublayer(gradientLayer, at: 0)
updateGradient()
}
private func updateGradient() {
gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupGradient()
}
}No código acima, GradientButton é um componente IBDesignable com propriedades IBInspectable startColor (v), endColor (v) e cornerRadius (v). Ao arrastar uma UIView para a tela do IB e alterar a classe para GradientButton no Identity Inspector, um botão com gradiente será exibido na tela em tempo real. Todas as propriedades IBInspectable aparecerão no painel Attributes Inspector à direita.
Importante: @IBDesignable compila todo o código para exibição no IB, portanto, solicitações de rede ou operações longas não devem ser executadas dentro dele. Para separação, usa-se #if TARGET_INTERFACE_BUILDER (k) — compilação condicional que exclui o código não destinado ao IB.
O processo de transformação dos arquivos do Interface Builder desde a criação do nib até a exibição na tela inclui várias etapas. Compreender este ciclo ajuda a diagnosticar problemas relacionados ao IB.
Na etapa de compilação, o Xcode executa a ferramenta ibtool (k, fn) — um utilitário de linha de comando para compilar arquivos .storyboard e .xib em formato nib binário. O ibtool também realiza validação: verifica a correção das restrições, a existência de todas as classes, os tipos de conexão IBOutlet/IBAction. Erros de validação são exibidos no Issue Navigator do Xcode.
O arquivo .nib final é colocado no pacote da aplicação na pasta .nib (s). O tamanho do arquivo nib é significativamente menor que o XML original: o formato binário usa uma representação otimizada com substituição de strings por tokens e compressão de valores numéricos. A compressão típica é de 50–60% do tamanho XML original.
Em tempo de execução, o nib é carregado através de UINib(nibName:bundle:) (k) ou automaticamente através de UIStoryboard.instantiateViewController(withIdentifier:) (k). O processo de carregamento inclui:
awakeFromNib() (fn) para cada objeto — ponto de entrada para configuração pós-carregamentoO método awakeFromNib() (fn) é chamado depois que todos os IBOutlets já estão definidos, mas antes do primeiro layoutSubviews. Isso é conveniente para configuração inicial: arredondar cantos, adicionar sombras, localizar texto. No entanto, todos os IBOutlets são garantidamente não-nil no awakeFromNib.
Com o lançamento do SwiftUI em 2019, os desenvolvedores iOS ganharam uma alternativa ao Interface Builder — um framework declarativo com Canvas Preview em tempo real. Vamos analisar as principais diferenças entre as duas abordagens.
Interface Builder gera uma descrição XML que é compilada em nib. A interface é criada visualmente; o código lida apenas com a lógica. O IB requer um limiar de entrada mais baixo para designers sem habilidades de programação, mas é difícil para revisão de código (alterações XML não são visíveis no diff).
SwiftUI Preview é desenvolvimento totalmente baseado em código. A interface é descrita em Swift, a pré-visualização é atualizada a cada salvamento. Sem XML, sem nib, sem risco de conexões IBOutlet quebradas. O SwiftUI Preview funciona mais rápido que o IB, pois não requer compilar um arquivo separado.
| Critério | Interface Builder (UIKit) | SwiftUI Preview |
|---|---|---|
| Formato de arquivo | XML (.storyboard / .xib) → nib binário | Código Swift (sem arquivo intermediário) |
| Pré-visualização | Tela do IB com atraso para visualizações complexas | Canvas Preview em tempo real |
| Suporte a versões iOS | iOS 2.0+ (todas as versões) | iOS 13+ |
| Merge no git | Problemático (um arquivo XML) | Simples (código Swift normal) |
| Dados dinâmicos | Através de IBOutlet + código | @State (k), @Observable (k) |
| Visualizações personalizadas | @IBDesignable (compilação) | SwiftUI View com PreviewProvider |
| Desempenho | Carregamento rápido de nib | Compilação Swift sob demanda |
Na prática, a escolha entre IB e SwiftUI Preview depende dos requisitos do projeto. Interface Builder é indispensável para aplicações UIKit com suporte a versões antigas do iOS, bem como para projetos comerciais onde designers trabalham no Xcode sem habilidades em Swift. O SwiftUI é preferível para novos projetos direcionados ao iOS 17+, onde a velocidade de desenvolvimento e a reatividade são importantes.
A Apple não planeja remover o Interface Builder do Xcode. Além disso, no Xcode 16, a empresa melhorou o desempenho da tela do IB e adicionou suporte a componentes SwiftUI através do UIViewRepresentable Bridge. Espera-se que o IB seja suportado pelo menos até 2030.
Anos de experiência em desenvolvimento iOS formaram um conjunto de recomendações que reduzem o número de problemas ao usar o Interface Builder em projetos comerciais.
Use XIB em vez de Storyboard para componentes reutilizáveis. Cada célula de tabela personalizada, cabeçalho ou rodapé deve estar em um XIB separado. Isso facilita o merge, acelera o carregamento e permite reutilizar componentes entre projetos através do Swift Package Manager ou CocoaPods.
Configure Storyboard References para dividir storyboards grandes em módulos. Em vez de um Main.storyboard com 100 telas, crie um storyboard para cada módulo (Auth, Profile, Feed) e conecte-os através de Storyboard Reference. Isso reduzirá o tempo de compilação do ibtool e simplificará o trabalho em equipe.
Evite conexões IBOutlet para File's Owner (k) sem verificação. Cada conexão deve ser weak (k) e opcional (o opcional implicitamente desembrulhado só é ótimo em playgrounds). Ao renomear um IBOutlet em uma visualização, o Xcode atualiza automaticamente a conexão, mas a edição manual de XML pode facilmente introduzir erros.
Show Connection Panel (k) após editar um arquivo IB — indicadores vermelhos sinalizam conexões quebradasUser Defined Runtime Attributes (k) para definir propriedades sem código: layer.cornerRadius, layer.borderWidth, tintColorIdentifier (k) a cada restrição no Size Inspector — isso ajuda a depurar conflitosimport UIKit
final class ProfileHeaderView: UIView {
@IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var bioLabel: UILabel!
@IBOutlet weak var editButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
avatarImageView.layer.cornerRadius = avatarImageView.bounds.width / 2
avatarImageView.layer.masksToBounds = true
nameLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bioLabel.font = UIFont.preferredFont(forTextStyle: .subheadline)
}
func configure(with profile: UserProfile) {
nameLabel.text = profile.fullName
bioLabel.text = profile.bio
/// Loading avatar via SDWebImage or Kingfisher
}
static func instantiateFromNib() -> ProfileHeaderView {
let nib = UINib(nibName: String(describing: self), bundle: nil)
return nib.instantiate(withOwner: nil).first as! ProfileHeaderView
}
}O exemplo mostra uma melhor prática para visualizações XIB: um método estático instantiateFromNib (fn) carrega a visualização do XIB com o mesmo nome da classe. O método awakeFromNib (fn) configura a UI (cantos arredondados, fontes), e o método configure(with:) (fn) aceita um modelo de dados para preenchimento. A separação de responsabilidades simplifica os testes e a reutilização.
Perguntas frequentes
Interface Builder é um editor visual para UIKit com formato Storyboard/XIB, funcionando através de arrastar e soltar. SwiftUI Preview é uma pré-visualização declarativa em tempo real onde a interface é descrita em código Swift. Ambas as ferramentas estão integradas no Xcode, mas o IB gera XML enquanto o SwiftUI compila Swift diretamente. O IB suporta iOS 2.0+, o SwiftUI suporta iOS 13+.
Não, o Interface Builder não é diretamente compatível com o SwiftUI. O SwiftUI usa sua própria sintaxe declarativa e Canvas Preview. No entanto, projetos UIKit criados através do IB podem ser integrados ao SwiftUI via UIViewRepresentable, e visualizações SwiftUI podem ser incorporadas ao UIKit via UIHostingController. Isso permite migrar gradualmente do IB para o SwiftUI.
@IBDesignable é uma anotação Swift que exibe uma UIView personalizada diretamente no Interface Builder em tempo real sem executar a aplicação. @IBInspectable é uma anotação para propriedades, adicionando-as ao painel Attributes Inspector do IB. Ambas as anotações aceleram o desenvolvimento de componentes de UI personalizados: basta alterar uma propriedade no inspetor e a mudança é imediatamente visível na tela.
O Auto Layout no Interface Builder define restrições através do menu Pin (margens, largura, altura) e do menu Align (centralização, linha de base). Cada restrição é uma relação matemática entre visualizações. O IB exibe erros com linhas vermelhas e conflitos com avisos amarelos. As Size Classes no IB permitem especificar diferentes restrições para diferentes dispositivos e orientações sem escrever código.
IBOutlet é uma anotação para uma referência a um elemento da UI a partir do código (por exemplo, @IBOutlet weak var label: UILabel!). IBAction é uma anotação para um método chamado em um evento (por exemplo, @IBAction func buttonTapped(_ sender: UIButton)). A conexão é criada através de Ctrl+arrastar da tela do IB para o arquivo do controlador. O Xcode gera automaticamente o código de conexão ao soltar o mouse.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também