Method Swizzling

Episode #124 | 16 minutes | published on 06/19/2014
Subscribers Only
In this episode we delve into the wonderful Objective-C runtime in order to replace method implementations with our own. Using this technique we can add or change behavior to existing classes, which can be extremely useful for Aspect Oriented Programming (logging/benchmarking), or analytics.

Episode Links

Swizzle Helper

First, we create a quick helper method to make swizzling a bit easier to use...

#import "FKBSwizzler.h"
#import <objc/runtime.h>

@implementation FKBSwizzler

+ (void)swizzleClass:(Class)class selector:(SEL)originalSelector newSelector:(SEL)newSelector {
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method newMethod = class_getInstanceMethod(class, newSelector);

    BOOL methodAdded = class_addMethod(class, originalSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
    if (methodAdded) {
        class_addMethod(class, newSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, newMethod);
    }
}

@end

We can use this to swizzle selectors on the same class, which is the majority use case.

Swizzling in Category Methods

The best way to swizzle methods on a class is to create a category on that class. You define the new method (using your prefix) and also implement + load so the swizzle happens early in the app's lifecycle.

#import "Foo+Swizzling.h"
#import "FKBSwizzler.h"

@implementation Foo (Swizzling)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [FKBSwizzler swizzleClass:self
                         selector:@selector(bar)
                      newSelector:@selector(fkb_bar)];
    });
}

- (void)fkb_bar {
    NSLog(@"---- BAR Being called ---");
    [self fkb_bar];
    NSLog(@"---- BAR finished --- ");
}

The benefit here is that this category applies the behavior itself, so it is quite modular. If you decide you don't want this behavior you simply remove the file from your project and the feature goes away.

blog comments powered by Disqus