Skip to content

Instantly share code, notes, and snippets.

@mikeash
Created February 4, 2018 03:26
Show Gist options
  • Select an option

  • Save mikeash/c51b5b31f672a8ef967f203c4dee4e98 to your computer and use it in GitHub Desktop.

Select an option

Save mikeash/c51b5b31f672a8ef967f203c4dee4e98 to your computer and use it in GitHub Desktop.

Revisions

  1. mikeash created this gist Feb 4, 2018.
    61 changes: 61 additions & 0 deletions omniswizzle.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    @import Foundation;
    @import ObjectiveC;


    static NSMutableSet *swizzledClasses;
    static NSMutableDictionary *swizzledBlocks; // Class -> SEL (as string) -> block
    static IMP forwardingIMP;
    static dispatch_once_t once;

    void Swizzle(Class c, SEL sel, void (^block)(NSInvocation *)) {
    dispatch_once(&once, ^{
    swizzledClasses = [NSMutableSet set];
    swizzledBlocks = [NSMutableDictionary dictionary];
    forwardingIMP = class_getMethodImplementation([NSObject class], @selector(thisReallyShouldNotExistItWouldBeExtremelyWeirdIfItDid));
    });

    if(![swizzledClasses containsObject: c]) {
    SEL fwdSel = @selector(forwardInvocation:);
    Method m = class_getInstanceMethod(c, fwdSel);
    __block IMP orig;
    IMP imp = imp_implementationWithBlock(^(id self, NSInvocation *invocation) {
    NSString *selStr = NSStringFromSelector([invocation selector]);
    void (^block)(NSInvocation *) = swizzledBlocks[c][selStr];
    if(block != nil) {
    NSString *originalStr = [@"omniswizzle_" stringByAppendingString: selStr];
    [invocation setSelector: NSSelectorFromString(originalStr)];
    block(invocation);
    } else {
    ((void (*)(id, SEL, NSInvocation *))orig)(self, fwdSel, invocation);
    }
    });
    orig = method_setImplementation(m, imp);
    [swizzledClasses addObject: c];
    }

    NSMutableDictionary *classDict = swizzledBlocks[c];
    if(classDict == nil) {
    classDict = [NSMutableDictionary dictionary];
    swizzledBlocks[(id)c] = classDict;
    }
    classDict[NSStringFromSelector(sel)] = block;

    Method m = class_getInstanceMethod(c, sel);
    NSString *newSelStr = [@"omniswizzle_" stringByAppendingString: NSStringFromSelector(sel)];
    SEL newSel = NSSelectorFromString(newSelStr);
    class_addMethod(c, newSel, method_getImplementation(m), method_getTypeEncoding(m));
    method_setImplementation(m, forwardingIMP);
    }

    int main(int argc, const char * argv[]) {
    @autoreleasepool {
    Swizzle([NSBundle class], @selector(objectForInfoDictionaryKey:), ^(NSInvocation *inv) {
    NSLog(@"invocation is %@ - calling now", inv);
    [inv invoke];
    NSLog(@"after");
    });

    NSLog(@"%@", [[NSBundle bundleForClass: [NSString class]] objectForInfoDictionaryKey: (__bridge NSString *)kCFBundleVersionKey]);
    }
    return 0;
    }