Method Swizzling in iOS and Android Development: Key Concepts, Techniques, and How It Works

Author: IT Sectr Published: 2026-05-17 Reading time: 9 min

Method Swizzling is a runtime technique where implementations of two class methods are swapped at runtime. It allows overriding or supplementing the behavior of a system method without creating a subclass or modifying the source code. The technique has found its greatest application in iOS development with Objective-C, but analogs exist in Kotlin/Android through reflection. According to NSHipster Guide by Mattt, 2024, swizzling is one of the most powerful, yet most dangerous mechanisms of the Objective-C Runtime.

Key Takeaways

  • Method Swizzling — swapping implementations of two Objective-C methods at runtime via sel_registerName and method_exchangeImplementations.
  • Objective-C Runtime enables swizzling through dynamic dispatch via objc_msgSend and the dispatch table.
  • Swizzling on Android is implemented via Java Reflection with implementation replacement in dex files or through the Gradle Transform API.
  • Risks of swizzling — conflicts between libraries, incompatibility with iOS updates, crashes when method signatures change.
  • Safe swizzling requires dispatch_once, atomicity, and calling the original implementation inside the swizzled method.

What is Method Swizzling?

Method Swizzling is a runtime technique that swaps the implementations of two Objective-C methods. After swizzling, calling originalSelector executes the code of swizzledSelector, and vice versa. This is possible thanks to the architecture of the Objective-C Runtime, where each selector (SEL) is associated with an implementation (IMP) via a dispatch table — a table that can be modified at runtime.

The term “swizzling” was introduced in the Cocoa developer community in the early 2000s. The technique gained widespread recognition thanks to libraries such as: AFNetworking (swizzling UIWebView to track loading), Aspects (AOP framework based on swizzling), and FLEX (debugging tool that swizzles system methods for inspection). Today, swizzling is used implicitly in most iOS applications — through monitoring and analytics libraries.

An important property of swizzling is globality: the implementation replacement occurs at the class level, not the instance level. If a library swizzles the UIViewController.viewDidLoad method, it affects ALL UIViewController instances in the application, including system ones. This is both the strength of swizzling — one line of code changes the entire application’s behavior — and the main source of bugs.

How Method Swizzling Works in Objective-C

Objective-C Runtime stores a dispatch table in each class — a dictionary where the key is SEL (method identifier) and the value is IMP (pointer to the implementation function). When an application sends a message to an object, objc_msgSend performs a linear search through this table. Method Swizzling replaces the IMP of one SEL with the IMP of another SEL, redirecting calls.

objective-c
// Safe method swizzling implementation
@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

The key function is method_exchangeImplementations(Method, Method). It atomically swaps the IMPs of two Method objects. After the call, the class dispatch table is modified: calling original executes the swizzled code, calling swizzled executes the original code. The SafeSwizzle category adds this method to all NSObject instances, allowing any class to perform swizzling.

A safe swizzling implementation requires calling the original implementation inside the swizzled version. Otherwise, the original method behavior is permanently lost. The correct pattern is to save the original IMP before the swap and call it in the swizzled method:

objective-c
// Swizzling with original implementation call
- (void)swizzled_viewDidLoad {
    // 1. Calling the original implementation
    [self swizzled_viewDidLoad];

    // 2. Additional logic after the original call
    NSLog("viewDidLoad executed, swizzling active");
}

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

dispatch_once guarantees that swizzling executes exactly once during the application’s lifetime. Re-swizzling the same method will lead to infinite recursion: the swizzled method will call itself. +load is called when the class is loaded into the runtime — it’s a safe point for swizzling that executes before the main application code.

Anatomy of the Dispatch Table

Dispatch table of an Objective-C class is an array of method_t structures containing SEL, IMP, and return type. method_exchangeImplementations simply swaps two IMP pointers in this table. Important: swizzling works only at the class level, not the protocol level. If a method is defined in a protocol but not implemented, the dispatch table contains no entry for swizzling.

Performance Impact of Swizzling

Swizzling overhead is minimal — swapping two IMP pointers in the dispatch table takes a few nanoseconds. After swizzling, method dispatch is not slowed down: objc_msgSend finds the IMP in the same O(1) time as before swizzling. The only additional operation is a method cache check on the first call after the swap. According to Apple Performance Team data, swizzling does not affect application performance.

Method Swizzling Use Cases in iOS

Method Swizzling is used in three main scenarios: monitoring and analytics (tracking viewDidLoad, viewDidAppear for automatic event sending), AOP interception (logging parameters of all method calls), and hotfix (fixing a production bug without App Store Review via libraries like JSPatch).

  • Automatic analytics — swizzling UIViewController.viewDidAppear to send screen view events without duplicating code in every controller.
  • Network request logging — swizzling NSURLSession.resume to track all HTTP requests, including those from third-party libraries.
  • AOP (Aspect-Oriented Programming) — the Aspects library swizzles methods and executes a block of code before/after/instead of the original call.
  • Hotfix — replacing the implementation of a buggy method with a fixed one without rebuilding the application (banned by App Review since 2020).
  • Testing and mocks — OCMock uses swizzling to replace methods with mock implementations in unit tests.

Each of these scenarios works because swizzling is applied centrally. An analytics library performs swizzling once in +load, and all UIViewController instances in the application start sending events. The developer doesn’t need to add code to every controller — this reduces duplication and the risk of errors.

Method Swizzling on Android: Reflection and Bytecode Manipulation

On Android, method swizzling in the classic Objective-C sense is impossible — Java/Kotlin use static dispatch via vtable. However, mechanisms exist that achieve a similar effect: Java Reflection for runtime implementation replacement and the Gradle Transform API / ASM for bytecode modification at build time.

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

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

// Replacing implementation at runtime via reflection
fun swizzleLog() {
    val originalMethod = Logger::class.java
        .getDeclaredMethod("log")
    originalMethod.isAccessible = true

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

    // Substitution via inline function
    println("swizzled: log intercepted")
}

This code replaces the behavior of the log() method via Java Reflection: getDeclaredMethod accesses the private implementation, isAccessible disables access checks. Instead of directly calling log(), a wrapper is called that performs additional logic. However, Android optimizes hot methods via JIT — reflection may not work on already compiled AOT segments.

A more reliable approach is bytecode manipulation via the Gradle Transform API or AGP (Android Gradle Plugin) with the ASM library. Bytecode modification is performed at compile time: ASM adds calls to every method in the class. This is how code coverage tools (JaCoCo) and performance monitoring tools (Firebase Performance Monitoring) work.

Risks and Best Practices of Method Swizzling

Method Swizzling is a high-risk technique. Conflicts between libraries: if two libraries swizzle the same method, execution order is not guaranteed. Incompatibility with iOS updates: if Apple changes the signature or removes a method in a new iOS version, swizzling leads to crashes. Lack of visibility in code: swizzling is not visible in the class implementation, complicating debugging.

RiskDescriptionMitigation
Library conflictTwo libraries swizzle viewDidAppear — one breaks the otherCheck if the method is already swizzled via class_getInstanceMethod
RecursionRe-swizzling the same method causes an infinite loopAlways use dispatch_once
Signature changeApple changes the method signature in a new iOS — IMP mismatchTest on all supported iOS versions
InvisibilitySwizzling does not appear in the Xcode call stackDocument all swizzling operations in code
App ReviewApple rejects applications with undocumented swizzlingUse only public APIs and document the purpose

Best practices for safe swizzling include: always call the original implementation, perform swizzling strictly in +load via dispatch_once, name swizzled methods with a prefix (e.g., s_originalMethodName), and document each swizzling operation with its purpose. The Aspects library solves the conflict problem through chained execution of blocks before/after the original method.

Alternatives to Method Swizzling in Modern Development

Alternatives to method swizzling are preferable for production code due to predictability and safety. Delegates and protocols (UIApplicationDelegate, UITableViewDelegate) provide explicit extension points without modifying the runtime. Subclassing — creating a subclass of UIViewController overriding viewDidAppear — works predictably and has no conflicts.

SwiftUI and Combine eliminate the need for swizzling: modifiers (onAppear, onChange) add behavior declaratively, without overriding methods. In Android Jetpack Compose achieves the same through effects (LaunchedEffect, SideEffect) and modifiers. AOP frameworks (AspectJ for Android, InterposeKit for iOS) provide a safe alternative with compile-time weaving.

According to Apple WWDC 2024 data, the Swift runtime does not support method swizzling at the language level — @objc dynamic methods can only be swizzled through the Objective-C Runtime. Swift applications that do not use @objc are completely protected from accidental swizzling by third-party libraries. This makes Swift safer but limits runtime instrumentation capabilities.

Declarative Alternatives in SwiftUI and Compose

SwiftUI modifiers (onAppear, onChange, onReceive) and Jetpack Compose effects (LaunchedEffect, SideEffect, DisposableEffect) completely replace swizzling for UI tasks. They provide a declarative, predictable, and testable way to add cross-cutting behavior without modifying the dispatch table. In new projects, Apple and Google recommend this approach instead of runtime interception.

Frequently Asked Questions

Is Method Swizzling safe for production?

Method Swizzling is acceptable for production when following the rules: dispatch_once for single execution, calling the original implementation, testing on all iOS versions, and documentation. For simple tasks, it’s better to use delegates or subclassing. Swizzling in production is justified for monitoring and analytics libraries.

How is Swizzling different from AOP?

Method Swizzling is a specific technique for replacing IMPs in the dispatch table. AOP (Aspect-Oriented Programming) is a paradigm in which swizzling can be used as one of the mechanisms. AOP also includes compile-time weaving (AspectJ), proxy-based interception (Spring AOP), and code generation.

How to debug problems caused by Swizzling?

Use a breakpoint in objc_msgSend to track all messages. Add a symbolic breakpoint on method_exchangeImplementations with a condition on the class name. The FLEX tool shows which class methods are swizzled. For systematic checking, use an lldb script that outputs the class dispatch table.

Does Swizzling work in Swift?

Swift does not support swizzling at the language level. Method Swizzling only works for methods marked @objc dynamic, which are compiled through the Objective-C Runtime. Pure Swift methods (without @objc) use static dispatch and cannot be swizzled — their dispatch table is not accessible for modification.

Which iOS libraries use Swizzling?

Firebase Analytics (swizzling viewDidAppear for automatic screen tracking), Amplitude, Mixpanel, FLEX (UI inspection), OHHTTPStubs (network request mocking), Aspects (AOP framework). All of them perform swizzling in +load via dispatch_once with a call to the original implementation.

Summary

  • Method Swizzling — swapping IMPs of two methods in the Objective-C Runtime dispatch table via method_exchangeImplementations.
  • dispatch_once is mandatory to prevent re-swizzling and recursion.
  • Calling the original implementation inside the swizzled method is a mandatory safety rule.
  • On Android, swizzling is replaced by reflection or bytecode manipulation via Gradle Transform / ASM.
  • Risks — library conflicts, incompatibility with iOS versions, invisibility in the debugger, and App Review ban on hotfixes.
  • Alternatives — delegates, subclassing, SwiftUI modifiers, Jetpack Compose effects.
  • Swift methods without @objc dynamic are protected from swizzling, which improves stability but limits runtime instrumentation.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also