draw(_:) e drawRect — o que são, chamada e sobrescrita

Autor: IT Sectr Publicado: 2026-07-20 Tempo de leitura: 7 min

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(_:) — método UIView para desenho personalizado via Core Graphics, não chamado diretamente pelo desenvolvedor
  • drawRect: — equivalente de draw(_:) em Objective-C, sintaticamente diferente, funcionalmente idêntico
  • CGContext — contexto gráfico disponível dentro de draw(_:) para todas as operações de desenho
  • setNeedsDisplay() — a única forma correta de solicitar um redesenho de draw(_:) pelo desenvolvedor
  • UIGraphicsGetCurrentContext() — função para obter o contexto atual dentro de draw(_:), passo obrigatório antes de desenhar

O que é draw(_:) / drawRect

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.

Assinatura do método em Swift e Objective-C

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(_:).

objective-c
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    CGContextFillRect(context, rect);
}

Quando o sistema chama draw(_:)

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.

  • Primeira renderização — quando a view é adicionada pela primeira vez à hierarquia e se torna visível na tela
  • setNeedsDisplay() — após chamar este método, o sistema redesenha no próximo ciclo de desenho
  • setNeedsDisplay(_:) — igual ao anterior, mas especificando um retângulo concreto para redesenho
  • contentMode — quando os bounds mudam, se contentMode exigir redesenho (por exemplo, .redraw)
  • setNeedsLayout() — em alguns casos, após a reorganização das subviews, o redesenho pode ser necessário

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(_:).

Como sobrescrever draw(_:) em Swift

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.

swift
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.

A regra de idempotência de draw(_:)

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: em Objective-C e diferenças do 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ísticadraw(_:) (Swift)drawRect: (Objective-C)
Assinaturaoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
Chamada a supersuper.draw(rect)[super drawRect:rect]
ContextoUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
Parâmetro rectrect: CGRectCGRect rect
DesempenhoIdênticoIdê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.

Otimização do desenho em draw(_:)

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.

Minimize o número de operações de 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(_:).

Use UIBezierPath para objetos vetoriais

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(_:).

swift
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()
}

Erros comuns ao trabalhar com draw(_:)

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.

  • Chamada direta a draw(_:) — nunca chame draw(_:) diretamente. Use setNeedsDisplay() para solicitar um redesenho. A chamada direta quebra o cache e pode levar a uma exibição incorreta.
  • Cálculos pesados dentro de draw(_:) — draw(_:) deve ser o mais leve possível. Crie UIBezierPath, imagens e outros objetos pesados fora do método, inicializando-os uma única vez.
  • Criação de objetos dentro de draw(_:) — construções de UIColor, UIFont e UIGraphicsImageRenderer dentro de draw(_:) criam carga desnecessária de memória. Mova a criação de objetos para propriedades da classe.
  • Ignorar o parâmetro rect — rect especifica a área que precisa de redesenho. Desenhar fora de rect é descartado pelo sistema, mas consome recursos. Verifique a interseção com rect antes de desenhar.
  • Falta de super.draw(rect) — embora a implementação de UIView seja vazia, a Apple recomenda chamar super.draw(rect) para compatibilidade com futuras mudanças do UIKit.

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

Pode-se chamar draw(_:) diretamente?

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.

Como drawRect: difere de draw(_:)?

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().

Por que draw(_:) não é chamado para um UIView vazio?

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.

Com que frequência o sistema chama draw(_:)?

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.

É necessário chamar super.draw(rect) em Swift?

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

  • draw(_:) / drawRect — o principal método de desenho de UIView em Swift e Objective-C, chamado automaticamente pelo sistema
  • CGContext — contexto Core Graphics disponível dentro de draw(_:) via UIGraphicsGetCurrentContext()
  • setNeedsDisplay() — a forma correta de solicitar um redesenho; a chamada direta a draw(_:) é proibida
  • Idempotência — draw(_:) deve produzir o mesmo resultado com os mesmos dados de entrada para cache adequado
  • UIBezierPath — crie caminhos fora de draw(_:) para minimizar a carga de CPU em cada chamada
  • Parâmetro rect — contém a área de redesenho; use interseção para otimizar — não desenhe fora dele
  • Perfilamento — verifique o desempenho de draw(_:) via Instruments Core Animation para identificar operações lentas

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.

Discutir o projeto

Leia também