Skip to content

Instantly share code, notes, and snippets.

@swillits
Last active August 29, 2015 14:10
Show Gist options
  • Save swillits/4a046bd95aca28935c31 to your computer and use it in GitHub Desktop.
Save swillits/4a046bd95aca28935c31 to your computer and use it in GitHub Desktop.
//
// 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