advantis
6/15/2013 - 10:53 AM

Playing around dynamic metod replacement on per-instance basis (think Decorator using runtime)

Playing around dynamic metod replacement on per-instance basis (think Decorator using runtime)

//
//  Copyright © 2013 Advantis
//

#import "NSObject+ADVDynamicMethodOverride.h"
#import <objc/runtime.h>

static const char *SubclassPrefix = "ADVOverriding";

@implementation NSObject (ADVDynamicMethodOverride)

- (BOOL) replaceMethod:(SEL)selector withBlock:(id)block
{
    Class class = object_getClass(self);
    const char *className = class_getName(class);
    if (className != strstr(className, SubclassPrefix))
    {
        // Create dynamic subclass
        char *subclassName;
        asprintf(&subclassName, "%s_%s", SubclassPrefix, className);
        Class subclass = objc_getClass(subclassName) ?: objc_allocateClassPair(class, subclassName, 0);
        free(subclassName);

        if (Nil == subclass) return NO;

        // OPTIONAL: Hide the existence of this dynamic subclass
        IMP classImp = imp_implementationWithBlock(^(__unused id this){
            return class;
        });
        class_addMethod(subclass, @selector(class), classImp, "@@:");

        objc_registerClassPair(subclass);
        object_setClass(self, subclass);
        class = object_getClass(self);
    }


    Method method = class_getInstanceMethod(class, selector);
    if (NULL == method) return NO;

    IMP imp = imp_implementationWithBlock(block);
    const char *types = method_getTypeEncoding(method);
    return class_addMethod(class, selector, imp, types);
}

@end
//
//  Copyright © 2013 Advantis
//

#import <Foundation/Foundation.h>

// typedef id(^ADVMethodImp)(id super, ...);

@interface NSObject (ADVDynamicMethodOverride)

- (BOOL) replaceMethod:(SEL)selector withBlock:(id)block;

@end