Otimização de desempenho de aplicativos Swift: dicas e exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução

O desempenho de aplicativos móveis e desktop é um fator chave que influencia a experiência do usuário. Os usuários esperam que os aplicativos sejam executados de forma rápida, suave e sem atrasos. Para desenvolvedores Swift que criam aplicativos para o ecossistema Apple (iOS, macOS, watchOS, tvOS), a otimização de desempenho torna-se não apenas desejável, mas uma tarefa obrigatória. Neste artigo, veremos os principais métodos para otimizar o desempenho de aplicativos Swift, desde o gerenciamento de memória até o trabalho eficiente com multithreading. Você aprenderá como evitar erros comuns e tornar seu aplicativo o mais rápido possível.



1. Gerenciamento de Memória e ARC

Swift usa Contagem Automática de Referências (ARC) para gerenciamento de memória. No entanto, o uso inadequado do ARC pode levar a vazamentos de memória e redução de desempenho. O principal problema são os ciclos de retenção.



1.1. Evite Ciclos de Retenção

Ciclos de retenção ocorrem quando dois objetos fazem referência um ao outro e o ARC não consegue desalocar a memória deles. Use weak ou unowned para quebrar o ciclo.

class Person {    let name: String    var apartment: Apartment?    init(name: String) { self.name = name }    deinit { print("\\(name) desalocado") }}

class Apartment { let unit: String weak var tenant: Person? // weak previne um ciclo de retenção init(unit: String) { self.unit = unit } deinit { print("Apartamento \\(unit) desalocado") }}

var john: Person? = Person(name: "João")var unit4A: Apartment? = Apartment(unit: "4A")john?.apartment = unit4Aunit4A?.tenant = johnjohn = nilunit4A = nil// Ambos os objetos serão desalocados


1.2. Use Tipos de Valor (Structs) em Vez de Tipos de Referência (Classes)

Structs são armazenadas na pilha, o que é mais rápido que o armazenamento no heap para classes. Use structs para dados pequenos e imutáveis.

struct Point {    var x: Double    var y: Double}

class PointClass { var x: Double var y: Double init(x: Double, y: Double) { self.x = x self.y = y }}

// Teste de desempenholet count = 1_000_000var start = CFAbsoluteTimeGetCurrent()var points = [Point](repeating: Point(x: 0, y: 0), count: count)for i in 0..<count { points[i].x = Double(i)}print("Structs: \\(CFAbsoluteTimeGetCurrent() - start) segundos")

start = CFAbsoluteTimeGetCurrent()var pointClasses = [PointClass]()for i in 0..<count { let p = PointClass(x: Double(i), y: 0) pointClasses.append(p)}print("Classes: \\(CFAbsoluteTimeGetCurrent() - start) segundos")


2. Otimizando o Trabalho com Multithreading (GCD)

Grand Central Dispatch (GCD) é uma ferramenta poderosa para executar tarefas em paralelo. O uso inadequado pode levar a deadlocks e redução de desempenho.



2.1. Use as Filas Corretas

Para tarefas em segundo plano, use filas globais com Quality of Service (QoS):

  • .userInteractive — para tarefas que exigem uma resposta imediata (ex.: animações).
  • .userInitiated — para tarefas iniciadas pelo usuário (ex.: carregamento de dados).
  • .utility — para tarefas de longa duração (ex.: processamento de arquivos).
  • .background — para tarefas que não afetam a interface do usuário (ex.: sincronização).
DispatchQueue.global(qos: .userInitiated).async {    // Tarefa pesada    let result = performHeavyCalculation()    DispatchQueue.main.async {        // Atualizar a interface na thread principal        self.updateUI(with: result)    }}


2.2. Evite Bloquear a Thread Principal

Todas as operações relacionadas à interface do usuário devem ser executadas na thread principal. Mova cálculos pesados e rede

Blogs

Book Recommendations