Por que o Swift está lento? Entendendo o desempenho
\n\nVocê já iniciou seu aplicativo Swift e sentiu que ele estava funcionando… bem, como uma lesma na hora do rush? A tela trava, as animações ficam instáveis e os usuários já estão prontos para dar uma estrela na App Store. Dor familiar? Bem-vindo ao clube!
\n\nSwift é uma linguagem rápida. A Apple prometeu isso e, em 90% dos casos, é verdade. Mas há um detalhe: até a linguagem mais poderosa pode ser "sufocada" por arquitetura ruim, vazamentos de memória ou algoritmos ineficientes. Neste artigo, não vamos dar aulas chatas. Em vez disso, vou mostrar ferramentas e técnicas reais que transformarão seu aplicativo de tartaruga em guepardo.
\n\nProntos? Vamos lá!
\n\nFerramentas de perfilamento: seu raio-X para o código
\n\nAntes de otimizar qualquer coisa, você precisa entender o que exatamente está lento. Adivinhar não é uma boa estratégia. É aqui que o perfilamento de código Swift entra em ação.
\n\nXcode Instruments — seu melhor amigo
\n\nO Xcode tem um conjunto de ferramentas integrado — Instruments. É como uma ressonância magnética para seu aplicativo: mostra cada detalhe, cada chamada de função e cada byte de memória. Inicia-se facilmente: Product > Profile (ou Cmd + I).
Aqui estão três modelos mais úteis:
\n\n- \n
- Time Profiler — mostra quais funções consomem mais tempo de CPU. \n
- Allocations — rastreia alocação e liberação de memória. \n
- Leaks — detecta vazamentos de memória (sim, no Swift eles também acontecem!). \n
Exemplo: você executa o Time Profiler, rola uma tabela — e vê que 70% do tempo vai para tableView(_:cellForRowAt:). Isso é um sinal: é hora de otimizar as células.
Signposts e os_log: perfilamento sem Instruments
\n\nInstruments é poderoso, mas nem sempre está à mão. Às vezes, você precisa medir rapidamente o desempenho diretamente no código. É aqui que os Signposts (iOS 12+) ajudam:
\n\nimport os.signpost\n\nlet log = OSLog(subsystem: "com.yourapp.networking", category: .pointsOfInterest)\nlet signpostID = OSSignpostID(log: log)\n\nos_signpost(.begin, log: log, name: "fetchData", signpostID: signpostID)\n// seu código de carregamento de dados\nos_signpost(.end, log: log, name: "fetchData", signpostID: signpostID)\n\n\nDepois, abra o Instruments, selecione os_signpost — e veja os timestamps. Bonito, né?
\n\nOtimização de código Swift: do simples ao complexo
\n\nAgora que sabemos onde estão os gargalos, vamos corrigi-los. Dividi as dicas em três níveis: para iniciantes, para experientes e para profissionais.
\n\n1. Nível básico: o que qualquer um pode fazer
\n\nVamos começar pelo óbvio, mas frequentemente esquecido.
\n\nUse value types (struct) em vez de reference types (class)
\n\nIsso é clássico no Swift. Struct é armazenado na pilha, class — no heap. A pilha é rápida, o heap é lento (precisa alocar memória, contar referências). Se seu objeto é pequeno e não requer herança — faça dele uma struct sem medo.
// Ruim (class)\nclass User {\n var name: String\n var age: Int\n init(name: String, age: Int) {\n self.name = name\n self.age = age\n }\n}\n\n// Bom (struct)\nstruct User {\n var name: String\n var age: Int\n}\n\n\nInicialização preguiçosa (lazy)
\n\nPor que criar um objeto se ele pode não ser necessário? Use lazy var:
class DataManager {\n lazy var networkService = NetworkService() // será criado apenas no primeiro acesso\n}\n\n\nEvite cópias desnecessárias
\n\nToda vez que você passa um array para uma função, o Swift pode copiá-lo (se for Array — value type). Use inout ou UnsafeMutablePointer para dados grandes.