draw(_:) / drawRect é um método da classe UIView (em Swift) e seu equivalente em Objective-C (drawRect:), responsável por renderizar o conteúdo da view usando Core Graphics. O sistema chama este método automaticamente quando a view aparece pela primeira vez na tela e após a chamada de setNeedsDisplay(). De acordo com a Documentação da Apple (2025), draw(_:) é o único método onde o desenvolvedor tem acesso ao contexto gráfico da tela atual para desenho personalizado. Sobrescrever draw(_:) dá controle total sobre a aparência do componente — desde formas geométricas simples até gráficos animados complexos.
Principais pontos
draw(_:) é um método de instância de UIView que UIKit chama para renderizar o conteúdo da view. Dentro deste método, o desenvolvedor obtém acesso ao contexto gráfico CGContext e usa a API Core Graphics para desenhar linhas, preenchimentos, texto e imagens. drawRect: em Objective-C executa a mesma função, mas com sintaxe diferente: o único parâmetro é um CGRect especificando a área a ser redesenhada.
De acordo com a Apple Engineering (2024), draw(_:) funciona através de renderização por CPU em Bitmap Graphics Context, o que proporciona máxima flexibilidade, mas requer mais recursos em comparação com CALayer. A decisão de usar draw(_:) é tomada com base na complexidade dos gráficos e nos requisitos de desempenho.
Em Swift, o método é declarado como override func draw(_ rect: CGRect), onde rect é o retângulo que precisa ser redesenhado. Em Objective-C, a assinatura é - (void)drawRect:(CGRect)rect. O parâmetro rect pode ser menor que os bounds da view durante o redesenho parcial via setNeedsDisplay(_:).
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rect);
}
O sistema chama automaticamente draw(_:) em cenários estritamente definidos. Compreender esses gatilhos ajuda a evitar redesenhos desnecessários e otimizar o desempenho da view. Abaixo estão todos os casos de invocação automática do método.
A documentação da Apple adverte: nunca chame draw(_:) diretamente. O sistema decide quando realizar o desenho, e uma chamada direta interrompe o mecanismo interno de cache. Para solicitar um redesenho, use sempre setNeedsDisplay() ou setNeedsDisplay(_:).
Sobrescrever draw(_:) em Swift começa com a obtenção do contexto gráfico e as chamadas subsequentes ao Core Graphics. Recomenda-se criar métodos separados para blocos lógicos de desenho — isso melhora a legibilidade e testabilidade do código.
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
// Line parameters
context.setStrokeColor(UIColor.darkGray.cgColor)
context.setLineWidth(2.0)
// Drawing a triangle
context.move(to: CGPoint(x: rect.midX, y: rect.minY + 10))
context.addLine(to: CGPoint(x: rect.maxX - 10, y: rect.maxY - 10))
context.addLine(to: CGPoint(x: rect.minX + 10, y: rect.maxY - 10))
context.closePath()
context.strokePath()
}
Neste exemplo, draw(_:) desenha um triângulo com um contorno cinza escuro de 2 pixels de espessura. Chamar super.draw(rect) no início do método é recomendado pela Apple para preservar a lógica de desenho pai, embora a implementação padrão de draw(_:) em UIView seja vazia.
Cada chamada a draw(_:) deve produzir um resultado idêntico com os mesmos dados de entrada. Isso permite que o sistema armazene o resultado em cache e não chame draw(_:) novamente se o conteúdo da view não tiver mudado. Não use valores aleatórios, hora do sistema ou solicitações de rede dentro de draw(_:).
drawRect: é historicamente a primeira versão do método, surgida no iOS 2.0 com Objective-C. Em Swift, o método foi renomeado para draw(_:) usando o parâmetro externo _. Funcionalmente, os métodos são idênticos: ambos recebem um CGRect da área a redesenhar e usam UIGraphicsGetCurrentContext() para acessar o contexto gráfico.
| Característica | draw(_:) (Swift) | drawRect: (Objective-C) |
|---|---|---|
| Assinatura | override func draw(_ rect: CGRect) | - (void)drawRect:(CGRect)rect |
| Chamada a super | super.draw(rect) | [super drawRect:rect] |
| Contexto | UIGraphicsGetCurrentContext() | UIGraphicsGetCurrentContext() |
| Parâmetro rect | rect: CGRect | CGRect rect |
| Desempenho | Idêntico | Idêntico |
Ao migrar um projeto de Objective-C para Swift, renomear o método é uma das primeiras tarefas. O Xcode fornece um conversor automático, mas drawRect: requer atualização manual para draw(_:). De acordo com a Apple (2024), a versão Swift draw(_:) é preferível para novos projetos.
draw(_:) é executado na CPU, e uma implementação abaixo do ideal pode causar quedas de quadros e baixo desempenho. A Apple recomenda várias abordagens comprovadas para acelerar o desenho.
Cada operação do Core Graphics (move(to:), addLine(to:), strokePath) tem sobrecarga. Agrupe as operações e use CGPath para formas complexas — o caminho é criado uma vez e reutilizado em cada chamada a draw(_:).
UIBezierPath é um wrapper Objective-C sobre CGPath que fornece uma API simples para criar formas. Crie UIBezierPath com antecedência (por exemplo, no inicializador) e simplesmente chame fill() ou stroke() dentro de draw(_:).
private let starPath: UIBezierPath = {
let path = UIBezierPath()
// Building a star shape
path.move(to: CGPoint(x: 50, y: 0))
for i in 1...5 {
let angle = CGFloat(i) * 4 * CGFloat.pi / 5
path.addLine(to: CGPoint(x: 50 + 40 * cos(angle),
y: 50 + 40 * sin(angle)))
}
path.close()
return path
}()
override func draw(_ rect: CGRect) {
UIColor.systemYellow.setFill()
starPath.fill()
}
Os desenvolvedores frequentemente cometem os mesmos erros ao sobrescrever draw(_:). Conhecer esses padrões ajuda a evitar bugs e degradação de desempenho. Vamos ver os problemas mais comuns e suas soluções.
Seguindo estas regras, você garantirá um desenho personalizado estável e rápido em qualquer projeto iOS. Perfile draw(_:) através do Instruments (Core Animation) para ver o tempo real de execução e gargalos.
Perguntas frequentes
Não, a chamada direta a draw(_:) é proibida pela documentação da Apple. O sistema gerencia o ciclo de desenho por si só. Para solicitar um redesenho, use setNeedsDisplay(), que marca corretamente a view como precisando de atualização no ciclo de renderização mais próximo.
Funcionalmente estes métodos são idênticos. drawRect: é usado em Objective-C, draw(_:) em Swift. Ambos recebem um CGRect da área a redesenhar e usam o mesmo contexto Core Graphics via UIGraphicsGetCurrentContext().
A Apple otimiza a renderização: se um UIView não tem draw(_:) sobrescrito, o sistema não cria um contexto bitmap para ele. Isso economiza memória. Se a sobrescrita existe mas o método não é chamado — verifique se o frame da view não é zero e se a view está visível.
Apenas quando necessário: primeira renderização, após setNeedsDisplay(), ao mudar os bounds com contentMode = .redraw. Em estado estático, draw(_:) não é chamado novamente, economizando recursos de CPU e bateria.
A Apple recomenda chamar super.draw(rect) no início do método sobrescrito. Embora a implementação atual de UIView seja vazia, a chamada a super garante compatibilidade com versões futuras do UIKit e é uma boa prática.
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