Method Swizzling no desenvolvimento iOS e Android: conceitos-chave, técnicas e princípio de funcionamento

Autor: IT Sectr Publicado: 2026-05-17 Tempo de leitura: 9 min

Method Swizzling é uma técnica de runtime onde as implementações de dois métodos de classe são trocadas durante a execução. Ela permite sobrescrever ou complementar o comportamento de um método do sistema sem criar uma subclasse ou modificar o código fonte. A técnica encontrou sua maior aplicação no desenvolvimento iOS com Objective-C, mas existem análogos em Kotlin/Android através de reflection. De acordo com NSHipster Guide by Mattt, 2024, o swizzling é um dos mecanismos mais poderosos, mas também mais perigosos do Objective-C Runtime.

Pontos principais

  • Method Swizzling — troca de implementações de dois métodos Objective-C em runtime através de sel_registerName e method_exchangeImplementations.
  • Objective-C Runtime permite o swizzling graças ao despacho dinâmico através de objc_msgSend e da dispatch table.
  • Swizzling no Android é implementado via Java Reflection com substituição de implementation em arquivos dex ou através do Gradle Transform API.
  • Riscos do swizzling — conflitos entre bibliotecas, incompatibilidade com atualizações do iOS, falhas ao alterar assinaturas de métodos.
  • Swizzling seguro requer dispatch_once, atomicidade e chamada à implementação original dentro do método swizzled.

O que é Method Swizzling?

Method Swizzling é uma técnica de runtime que troca as implementações de dois métodos Objective-C. Após o swizzling, chamar originalSelector executa o código de swizzledSelector, e vice-versa. Isso é possível graças à arquitetura do Objective-C Runtime, onde cada seletor (SEL) está associado a uma implementação (IMP) através de uma dispatch table — uma tabela que pode ser modificada durante a execução.

O termo “swizzling” foi introduzido na comunidade de desenvolvedores Cocoa no início dos anos 2000. A técnica ganhou amplo reconhecimento graças a bibliotecas como: AFNetworking (swizzling de UIWebView para rastrear carregamento), Aspects (framework AOP baseado em swizzling) e FLEX (ferramenta de depuração que swizzle métodos do sistema para inspeção). Hoje, o swizzling é usado implicitamente na maioria das aplicações iOS — através de bibliotecas de monitoramento e análise.

Uma propriedade importante do swizzling é a globalidade: a substituição da implementação ocorre ao nível da classe, não da instância. Se uma biblioteca swizzle o método UIViewController.viewDidLoad, afeta TODAS as instâncias de UIViewController na aplicação, incluindo as do sistema. Isto é tanto a força do swizzling — uma linha de código muda o comportamento de toda a aplicação — como a principal fonte de bugs.

Como o Method Swizzling funciona em Objective-C

Objective-C Runtime armazena em cada classe uma dispatch table — um dicionário onde a chave é SEL (identificador do método) e o valor é IMP (ponteiro para a função de implementação). Quando uma aplicação envia uma mensagem a um objeto, objc_msgSend realiza uma pesquisa linear nesta tabela. Method Swizzling substitui o IMP de um SEL pelo IMP de outro SEL, redirecionando as chamadas.

objective-c
// Implementação segura de method swizzling
@implementation NSObject (SafeSwizzle)

+ (void)swizzleClassMethod:(SEL)original
                  with:(SEL)swizzled {
    Class cls = [self class];
    SEL originalSel = original;
    SEL swizzledSel = swizzled;

    Method originalMethod = class_getInstanceMethod(cls, originalSel);
    Method swizzledMethod = class_getInstanceMethod(cls, swizzledSel);

    method_exchangeImplementations(originalMethod, swizzledMethod);
}

@end

A função chave é method_exchangeImplementations(Method, Method). Ela troca atomicamente os IMPs de dois objetos Method. Após a chamada, a dispatch table da classe é modificada: chamar original executa o código swizzled, chamar swizzled executa o código original. A categoria SafeSwizzle adiciona este método a todos os NSObject, permitindo que qualquer classe realize swizzling.

Uma implementação segura de swizzling requer chamar a implementação original dentro da versão swizzled. Caso contrário, o comportamento original do método é perdido permanentemente. O padrão correto é guardar o IMP original antes da troca e chamá-lo no método swizzled:

objective-c
// Swizzling com chamada à implementação original
- (void)swizzled_viewDidLoad {
    // 1. Chamada à implementação original
    [self swizzled_viewDidLoad];

    // 2. Lógica adicional após a chamada original
    NSLog("viewDidLoad executado, swizzling ativo");
}

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self swizzleClassMethod:@selector(viewDidLoad)
                            with:@selector(swizzled_viewDidLoad)];
    });
}

dispatch_once garante que o swizzling execute exatamente uma vez durante a vida da aplicação. Swizzlar novamente o mesmo método levaria a uma recursão infinita: o método swizzled chamaria a si mesmo. +load é invocado quando a classe é carregada no runtime — é um ponto seguro para swizzling que executa antes do código principal da aplicação.

Anatomia da dispatch table

A dispatch table de uma classe Objective-C é um array de estruturas method_t contendo SEL, IMP e tipo de retorno. method_exchangeImplementations simplesmente troca dois ponteiros IMP nesta tabela. Importante: o swizzling funciona apenas ao nível da classe, não do protocolo. Se um método está definido num protocolo mas não implementado, a dispatch table não contém uma entrada para swizzling.

Impacto do swizzling no desempenho

A sobrecarga do swizzling é mínima — trocar dois ponteiros IMP na dispatch table leva alguns nanossegundos. Após o swizzling, a chamada ao método não é retardada: objc_msgSend encontra o IMP no mesmo tempo O(1) que antes do swizzling. A única operação adicional é uma verificação da cache de métodos na primeira chamada após a troca. Segundo dados da Apple Performance Team, o swizzling não afeta o desempenho da aplicação.

Aplicações do Method Swizzling no iOS

Method Swizzling é usado em três cenários principais: monitoramento e análise (rastreamento de viewDidLoad, viewDidAppear para envio automático de eventos), interceção AOP (registo de parâmetros de todas as chamadas a métodos) e hotfix (correção de um bug em produção sem revisão da App Store através de bibliotecas como JSPatch).

  • Análise automática — swizzling de UIViewController.viewDidAppear para enviar eventos de screen view sem duplicar código em cada controlador.
  • Registo de pedidos de rede — swizzling de NSURLSession.resume para rastrear todos os pedidos HTTP, incluindo os de bibliotecas terceiras.
  • AOP (Programação Orientada a Aspetos) — a biblioteca Aspects swizzle métodos e executa um bloco de código antes/depois/em vez da chamada original.
  • Hotfix — substituição da implementação de um método com bugs por uma corrigida sem recompilar a aplicação (proibido pela App Review desde 2020).
  • Testes e mocks — OCMock usa swizzling para substituir métodos por implementações mock em testes unitários.

Cada um destes cenários funciona porque o swizzling é aplicado centralizadamente. Uma biblioteca de análise realiza o swizzling uma vez em +load, e todas as instâncias de UIViewController na aplicação começam a enviar eventos. O desenvolvedor não precisa adicionar código em cada controlador — isto reduz a duplicação e o risco de erros.

Method Swizzling no Android: reflection e manipulação de bytecode

No Android, o method swizzling no sentido clássico do Objective-C é impossível — Java/Kotlin usam despacho estático via vtable. No entanto, existem mecanismos que alcançam um efeito semelhante: Java Reflection para substituir implementações em runtime e Gradle Transform API / ASM para modificar o bytecode em tempo de compilação.

kotlin
// Swizzling no Android via reflection + companion object
class Logger {
    companion object {
        var originalImpl: (() -> Unit)? = null
    }

    fun log() {
        println("log original")
    }
}

// Substituição de implementação em runtime via reflection
fun swizzleLog() {
    val originalMethod = Logger::class.java
        .getDeclaredMethod("log")
    originalMethod.isAccessible = true

    Logger.originalImpl = {
        originalMethod.invoke(Logger())
    }

    // Substituição através de função inline
    println("swizzled: log intercetado")
}

Este código substitui o comportamento do método log() através de Java Reflection: getDeclaredMethod acede à implementação privada, isAccessible desativa as verificações de acesso. Em vez de chamar diretamente log(), é chamado um wrapper que executa lógica adicional. No entanto, o Android otimiza métodos quentes via JIT — a reflection pode não funcionar em segmentos AOT já compilados.

Uma abordagem mais fiável é a manipulação de bytecode através do Gradle Transform API ou AGP (Android Gradle Plugin) com a biblioteca ASM. A modificação do bytecode é realizada em tempo de compilação: ASM adiciona chamadas a cada método da classe. É assim que funcionam as ferramentas de cobertura de código (JaCoCo) e de monitoramento de desempenho (Firebase Performance Monitoring).

Riscos e melhores práticas do Method Swizzling

Method Swizzling é uma técnica de alto risco. Conflitos entre bibliotecas: se duas bibliotecas swizzlam o mesmo método, a ordem de execução não é garantida. Incompatibilidade com atualizações do iOS: se a Apple alterar a assinatura ou remover um método numa nova versão do iOS, o swizzling provoca falhas. Falta de visibilidade no código: o swizzling não é visível na implementação da classe, dificultando a depuração.

RiscoDescriçãoMitigação
Conflito de bibliotecasDuas bibliotecas swizzlam viewDidAppear — uma quebra a outraVerificar se o método já está swizzled através de class_getInstanceMethod
RecursãoSwizzlar novamente o mesmo método causa um loop infinitoUsar sempre dispatch_once
Alteração de assinaturaApple altera a assinatura do método num novo iOS — IMP não correspondeTestar em todas as versões iOS suportadas
InvisibilidadeO swizzling não aparece na pilha de chamadas do XcodeDocumentar todas as operações de swizzling no código
App ReviewApple rejeita aplicações com swizzling não documentadoUsar apenas APIs públicas e documentar o propósito

As melhores práticas para um swizzling seguro incluem: chamar sempre a implementação original, realizar o swizzling estritamente em +load através de dispatch_once, nomear os métodos swizzled com um prefixo (por exemplo, s_originalMethodName), documentar cada operação de swizzling com o seu propósito. A biblioteca Aspects resolve o problema de conflitos através da execução encadeada de blocos antes/depois do método original.

Alternativas ao Method Swizzling no desenvolvimento moderno

As alternativas ao method swizzling são preferíveis para código de produção devido à previsibilidade e segurança. Os delegados e protocolos (UIApplicationDelegate, UITableViewDelegate) fornecem pontos de extensão explícitos sem modificar o runtime. A subclasse — criar uma subclasse de UIViewController sobrescrevendo viewDidAppear — funciona de forma previsível e não tem conflitos.

SwiftUI e Combine eliminam a necessidade de swizzling: os modificadores (onAppear, onChange) adicionam comportamento de forma declarativa, sem sobrescrever métodos. No Android Jetpack Compose alcança o mesmo através de efeitos (LaunchedEffect, SideEffect) e modificadores. Os frameworks AOP (AspectJ para Android, InterposeKit para iOS) fornecem uma alternativa segura com weaving em tempo de compilação.

Segundo dados da Apple WWDC 2024, o runtime do Swift não suporta method swizzling ao nível da linguagem — os métodos @objc dynamic só podem ser swizzled através do Objective-C Runtime. As aplicações Swift que não usam @objc estão completamente protegidas contra swizzling acidental por bibliotecas terceiras. Isto torna o Swift mais seguro, mas limita as capacidades de instrumentação em runtime.

Alternativas declarativas em SwiftUI e Compose

Os modificadores do SwiftUI (onAppear, onChange, onReceive) e os efeitos do Jetpack Compose (LaunchedEffect, SideEffect, DisposableEffect) substituem completamente o swizzling para tarefas de UI. Fornecem uma forma declarativa, previsível e testável de adicionar comportamento transversal sem modificar a dispatch table. Em novos projetos, a Apple e a Google recomendam esta abordagem em vez da interceção em runtime.

Perguntas frequentes

O Method Swizzling é seguro para produção?

O Method Swizzling é aceitável para produção quando se seguem as regras: dispatch_once para execução única, chamada à implementação original, testes em todas as versões do iOS e documentação. Para tarefas simples, é melhor usar delegados ou subclasses. O swizzling em produção é justificado para bibliotecas de monitoramento e análise.

Qual a diferença entre Swizzling e AOP?

Method Swizzling é uma técnica específica para substituir IMPs na dispatch table. AOP (Programação Orientada a Aspetos) é um paradigma no qual o swizzling pode ser usado como um dos mecanismos. AOP também inclui weaving em tempo de compilação (AspectJ), interceção baseada em proxies (Spring AOP) e geração de código.

Como depurar problemas causados por Swizzling?

Usar um breakpoint em objc_msgSend para rastrear todas as mensagens. Adicionar um breakpoint simbólico em method_exchangeImplementations com uma condição sobre o nome da classe. A ferramenta FLEX mostra quais métodos da classe estão swizzled. Para uma verificação sistemática, usar um script lldb que mostre a dispatch table da classe.

O Swizzling funciona em Swift?

O Swift não suporta swizzling ao nível da linguagem. O Method Swizzling só funciona para métodos marcados com @objc dynamic, que são compilados através do Objective-C Runtime. Os métodos Swift puros (sem @objc) usam despacho estático e não podem ser swizzled — a sua dispatch table não está acessível para modificação.

Quais bibliotecas iOS usam Swizzling?

Firebase Analytics (swizzling de viewDidAppear para rastreamento automático de ecrãs), Amplitude, Mixpanel, FLEX (inspeção de UI), OHHTTPStubs (simulação de pedidos de rede), Aspects (framework AOP). Todas realizam swizzling em +load através de dispatch_once com chamada à implementação original.

Resumo

  • Method Swizzling — troca de IMPs de dois métodos na dispatch table do Objective-C Runtime através de method_exchangeImplementations.
  • dispatch_once é obrigatório para prevenir novo swizzling e recursão.
  • Chamar a implementação original dentro do método swizzled é uma regra de segurança obrigatória.
  • No Android, o swizzling é substituído por reflection ou manipulação de bytecode através de Gradle Transform / ASM.
  • Riscos — conflitos de bibliotecas, incompatibilidade com versões iOS, invisibilidade no depurador e proibição da App Review para hotfixes.
  • Alternativas — delegados, subclasses, modificadores do SwiftUI, efeitos do Jetpack Compose.
  • Os métodos Swift sem @objc dynamic estão protegidos contra swizzling, o que melhora a estabilidade mas limita a instrumentação em runtime.

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