Performance no IOS: Entendendo Dynamic Dispatch e Static Dispatch




- Static Dispatch (Despacho Estático): A decisão de qual método executar é feita em tempo de compilação.
- Dynamic Dispatch (Despacho Dinâmico): A decisão é adiada para o tempo de execução, o que permite maior flexibilidade, porém com um pequeno custo de performance.
Static Dispatch
No Static Dispatch, o compilador sabe exatamente qual método será chamado durante a compilação. Isso permite que ele realize otimizações como o inlining, que consiste em substituir a chamada de uma função pelo seu próprio código, eliminando a sobrecarga da chamada e melhorando o desempenho.
Características:
- Decidido em tempo de compilação.
- Sem custo de lookup (busca dinâmica em tempo de execução).
- Melhor performance.
- Não permite sobrescrita (overriding) de métodos.
Quando ocorre:
- Métodos marcados como final (não podem ser sobrescritos).
- Métodos em structs e enums (tipos por valor).
- Funções static.
- Métodos de classes marcados como final.
Dynamic Dispatch
Já no Dynamic Dispatch, a decisão sobre qual método será executado acontece em tempo de execução, com base no tipo real do objeto. Isso permite polimorfismo, ou seja, que subclasses sobrescrevam métodos da superclasse e que o comportamento mude conforme a instância usada.
Para realizar essa decisão, o sistema utiliza estruturas como a dispatch table (ou vtable, "virtual method table") — uma tabela interna que armazena ponteiros para os métodos que podem ser chamados dinamicamente. Quando um método é invocado, o sistema faz um lookup (busca) nessa tabela para descobrir qual versão do método deve ser executada.
Características:
- Decidido em tempo de execução.
- Permite sobrescrita de métodos.
- Pequeno custo de lookup na dispatch table/vtable.
- Suporte ao polimorfismo e runtime dinâmico.
Quando ocorre:
- Métodos de classes não marcados como final.
- Métodos marcados com @objc.
- Métodos declarados como dynamic.
O que são @objc e dynamic?
- @objc: Indica que o método ou propriedade pode ser acessado pelo runtime do Objective-C. Isso é necessário quando você precisa de compatibilidade com APIs escritas em Objective-C ou quando usa mecanismos como Selector, notificações (NotificationCenter) ou KVO (Key-Value Observing).
- dynamic: Informa explicitamente que o método deve usar dynamic dispatch, mesmo em um contexto onde o Swift usaria dispatch estático. Todo método dynamic também é @objc automaticamente.
Selector: Um selector é uma forma de referenciar métodos por nome (como uma string) no runtime do Objective-C. É amplamente usado para chamadas dinâmicas, como no performSelector, target-action e observadores.
Exemplo prático:


Como saber se é Dynamic ou Static Dispatch?
Uma forma rápida de saber:


Comparação de Performance Benchmark Simples:
import Foundation
class DynamicClass {
func compute() -> Int {
return 42
}
}
final class StaticClass {
func compute() -> Int {
return 42 }
}
struct StaticStruct {
func compute() -> Int {
return 42 }
}
func measure( label: String, block: ()-> Void) {
let start CFAbsoluteTimeGetCurrent()
block()
let diff CFAbsoluteTimeGetCurrent() start
print("\(label) took \(diff) seconds")
}
let dynamic DynamicClass()
let staticStruct = StaticStruct()
let staticClass StaticClass()
let iterations = 1_000_000
measure("Dynamic Dispatch") {
var result = 0
for in 0..<iterations {
result += dynamic.compute()
}
assert(result > 0)
}
measure("Static Dispatch (final class)") {
var result = 0
for } in 0..citerations {
result += staticClass.compute()
}
assert(result > 0)
measure("Static Dispatch (struct)”) {
var result =0
for _ in 0 ..siterations ( for result = staticStruct.compute()
}
assert(result > 0)
}
Resultados esperados:
- Static Dispatch: geralmente de 10% a 30% mais rápido dependendo do ambiente.
- Dynamic Dispatch: pequeno overhead devido ao lookup na vtable.
Quando se preocupar?
Deve-se considerar static dispatch em código de alto desempenho, como:
- Processamento gráfico.
- Algoritmos de machine learning no device.
- Processamento de áudio em tempo real.
- Uso de “final” não só melhora a performance, mas também expressa intenção de design (prevenção de herança).
Conclusão
O Dynamic Dispatch oferece flexibilidade e suporte ao polimorfismo — essencial na programação orientada a objetos. Por outro lado, o Static Dispatch proporciona máxima performance, sendo favorecido em cenários com struct, enum, métodos static ou final.
Entender como e quando cada tipo de dispatch ocorre não só ajuda a otimizar a performance da sua aplicação, como também contribui para um design mais claro, robusto e seguro.
No Swift, equilibrar o uso de value types (como structs) e reference types (classes) vai além da modelagem de dados: impacta diretamente o desempenho da aplicação.

.webp)


