Last active
August 29, 2015 14:10
-
-
Save swillits/4a046bd95aca28935c31 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
// | |
// main.m | |
// Probie | |
// | |
// Created by Seth Willits on 11/19/14. | |
// Copyright (c) 2014 Araelium Group. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
#import <objc/message.h> | |
void MethodSwizzle(Class c, SEL orig, SEL new) | |
{ | |
Method origMethod = class_getInstanceMethod(c, orig); | |
Method newMethod = class_getInstanceMethod(c, new); | |
if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { | |
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); | |
} else { | |
method_exchangeImplementations(origMethod, newMethod); | |
} | |
} | |
@interface Probie : NSObject | |
@end | |
@implementation Probie | |
#define BEGIN_PROBIE \ | |
NSTimeInterval _profilingT = NSDate.timeIntervalSinceReferenceDate; | |
#define END_PROBIE \ | |
_profilingT = (NSDate.timeIntervalSinceReferenceDate - _profilingT); \ | |
if (_profilingT > 0.01) NSLog(@"[PROF] %@: %f", NSStringFromSelector(_cmd), _profilingT); \ | |
+ (void)probeClass:(Class)class selector:(SEL)selector | |
{ | |
SEL newSel = NSSelectorFromString([@"swizzled_" stringByAppendingString:NSStringFromSelector(selector)]); | |
Method originalMethod = class_getInstanceMethod(class, selector); | |
SEL swizzledSelector = [self swizzledSelectorForClass:class selector:selector]; | |
if (!swizzledSelector) { | |
NSLog(@"Probie can't probe [%@ %@] because no swizzle equivalent exists", NSStringFromClass(class), NSStringFromSelector(selector)); | |
return; | |
} | |
IMP newImplementation = method_getImplementation(class_getInstanceMethod(self, swizzledSelector)); | |
if (class_addMethod(class, newSel, newImplementation, method_getTypeEncoding(originalMethod))) { | |
Method newMethod = class_getInstanceMethod(class, newSel); | |
method_exchangeImplementations(originalMethod, newMethod); | |
} | |
} | |
+ (SEL)swizzledSelectorForClass:(Class)class selector:(SEL)selector | |
{ | |
unsigned int count = 0; | |
Method * methods = class_copyMethodList(self, &count); | |
SEL swizzledSelector = nil; | |
Method originalMethod = class_getInstanceMethod(class, selector); | |
const char * originalMethodTypes = method_getTypeEncoding(originalMethod); | |
if (methods) { | |
for (unsigned int i = 0; i < count; i++) { | |
struct objc_method_description * desc = method_getDescription(methods[i]); | |
NSString * name = NSStringFromSelector(desc->name); | |
if ([name hasPrefix:@"swizzled_"]) { | |
if (strcmp(originalMethodTypes, desc->types) == 0) { | |
swizzledSelector = desc->name; | |
break; | |
} | |
} | |
} | |
free(methods); | |
} | |
return swizzledSelector; | |
} | |
- (void)swizzled_void_args0 | |
{ | |
BEGIN_PROBIE | |
{ | |
SEL newSel = NSSelectorFromString([@"swizzled_" stringByAppendingString:NSStringFromSelector(_cmd)]); | |
((void (*)(id, SEL))objc_msgSend)(self, newSel /* args */); | |
} | |
END_PROBIE | |
} | |
- (int)swizzled_int_args0 | |
{ | |
int retval; | |
BEGIN_PROBIE | |
{ | |
SEL newSel = NSSelectorFromString([@"swizzled_" stringByAppendingString:NSStringFromSelector(_cmd)]); | |
retval = ((int (*)(id, SEL))objc_msgSend)(self, newSel /* args */); | |
} | |
END_PROBIE | |
return retval; | |
} | |
@end | |
@interface Foo : NSObject | |
@end | |
@implementation Foo | |
- (void)test1 | |
{ | |
usleep(1e5); | |
} | |
- (int)test2 | |
{ | |
usleep(1e5); | |
return 2; | |
} | |
- (void)test3:(id)a | |
{ | |
usleep(1e5); | |
} | |
@end | |
int main(int argc, const char * argv[]) | |
{ | |
@autoreleasepool { | |
[Probie probeClass:[Foo class] selector:@selector(test1)]; | |
[Probie probeClass:[Foo class] selector:@selector(test2)]; | |
[Probie probeClass:[Foo class] selector:@selector(test3:)]; | |
Foo * foo = [[Foo alloc] init]; | |
[foo test1]; | |
[foo test2]; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment