Created
February 4, 2018 03:26
-
-
Save mikeash/c51b5b31f672a8ef967f203c4dee4e98 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment