Exploring Dynamic Method Injection in Swift
Tags: ios, swift, advanced, development
Published: 2023-12-06 15:25:07

---
title: Exploring Dynamic Method Injection in Swift
published: true
description: 
tags: ios, swift, advanced, development
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-12-05 22:18 +0000
---

## Introduction
Hello Swift enthusiasts! In today's article, we're diving into an intriguing aspect of Swift programming - dynamic method injection. This technique allows developers to add methods to classes or objects at runtime, offering a flexible approach to managing functionalities. We'll explore this concept through a code snippet that injects a method from one class into another.

## What is Method Injection?
Method Injection is a process where you dynamically add new methods to a class or an instance of a class at runtime. This is not typically a Swift-native approach, as Swift emphasizes type safety and compile-time checks. However, Swift's interoperability with Objective-C runtime offers a backdoor to achieve this.

## The Code Breakdown
Here's a brief overview of the code snippet we're examining:

### Class Definitions
- `ClassA`: Contains a `hello()` method that prints the class's name. `hello()` method must have `@objc` attribute because it will be user with Objective-C Runtime soon.
- `ClassB`: An empty class without any methods.

```swift
class ClassA {
    @objc
    func hello() {
        print("Hello, i'm " + String(describing: type(of: self)))
    }
}

class ClassB { }
```

### Method Injection Function
- `useMethod(sel:fromClass:inObject:)`: Injects the method from `fromClass` into `inObject`.
- It employs `class_getInstanceMethod` and `unsafeBitCast` to dynamically add the method to the object.

```swift
func useMethod(sel: Selector, fromClass: AnyClass, inObject: AnyObject) {
    
    guard let meth = class_getInstanceMethod(fromClass, sel) else {
        return
    }
    
    typealias ClosureType = @convention(c) (AnyObject, Selector) -> Void
    let imp = method_getImplementation(meth)
    let callMethod: ClosureType = unsafeBitCast(imp, to: ClosureType.self)
    callMethod(inObject, sel)
}
```

### Implementation
- An instance of `ClassA` is created and its `hello()` method is called.
- An instance of `ClassB` is then created, and the `hello` method from `ClassA` is injected and executed on it using `useMethod`.

```swift
let a = ClassA()
a.hello()

let b = ClassB()
useMethod(sel: #selector(ClassA.hello), fromClass:ClassA.self, inObject: b)
```

## Deep Dive into the Function
The `useMethod` function is where the magic happens. Let’s dissect it:
- It first checks if the method exists in the source class using `class_getInstanceMethod`.
- Once the method is obtained, it retrieves its implementation (`IMP`).
- This implementation is then cast to a closure of type `@convention(c) (AnyObject, Selector) -> Void` using `unsafeBitCast`.
- Finally, the method is invoked on the target object.

You can find full playground in [this gist](https://gist.github.com/neobeppe/a3a9021299b1ee21afa687c65a762a59).

## Why is This Important?
This method showcases an advanced level of Swift's capabilities, blending Swift's modern features with the underlying Objective-C runtime. It demonstrates how Swift can handle dynamic behavior, a feature often associated with more dynamic languages like Python or JavaScript.

## Cautions
While powerful, method injection should be used judiciously. It bypasses Swift's type safety and can lead to unpredictable behaviors or crashes if not handled properly. Always ensure that the method and the target object are compatible.

## Conclusion
Dynamic method injection in Swift, while not a common practice, opens doors to a range of possibilities for developers willing to explore the depths of the language. It exemplifies Swift's versatility and its seamless blend with Objective-C runtime, offering a unique approach to solving complex programming challenges.