Skip to content

Instantly share code, notes, and snippets.

@kwylez
Created September 21, 2012 15:15
Show Gist options
  • Save kwylez/3762103 to your computer and use it in GitHub Desktop.
Save kwylez/3762103 to your computer and use it in GitHub Desktop.
Method Swizzling
// json file
{
"Accounts":[{
"AccountNumber":"String content",
"Address":{
"Address1":"String content",
"Address2":"String content",
"City":"String content",
"State":"String content",
"ZipCode":"String content"
}],
"UniqueID":"String content",
"UserToken":"String content"
}
// utility method
void SwapMethods(Class aClass, SEL orig_sel, SEL alt_sel, BOOL forInstance) {
if (aClass != nil) {
Method orig_method = nil, alt_method = nil;
if (forInstance) {
orig_method = class_getInstanceMethod(aClass, orig_sel);
alt_method = class_getInstanceMethod(aClass, alt_sel);
} else {
orig_method = class_getClassMethod(aClass, orig_sel);
alt_method = class_getClassMethod(aClass, alt_sel);
}
// If both are found, swizzle them
if ((orig_method != nil) && (alt_method != nil)) {
method_exchangeImplementations(orig_method, alt_method);
} else {
NSLog(@"SwapMethods Error: Original %@, Alternate %@",
(orig_method == nil)?@" not found":@" found",
(alt_method == nil)?@" not found":@" found");
}
} else {
NSLog(@"SwapMethods Error: Class not found");
}
}
void SwapMethodsForDifferentClass(Class aClassSwappedTo, SEL orig_sel, Class aClassSwappedFrom, SEL alt_sel, BOOL forInstance) {
if (aClassSwappedTo != nil) {
Method orig_method = nil, alt_method = nil;
if (forInstance) {
orig_method = class_getInstanceMethod(aClassSwappedTo, orig_sel);
alt_method = class_getInstanceMethod(aClassSwappedFrom, alt_sel);
} else {
orig_method = class_getClassMethod(aClassSwappedTo, orig_sel);
alt_method = class_getClassMethod(aClassSwappedFrom, alt_sel);
}
// If both are found, swizzle them
if ((orig_method != nil) && (alt_method != nil)) {
method_exchangeImplementations(orig_method, alt_method);
} else {
NSLog(@"SwapMethods Error: Original %@, Alternate %@",
(orig_method == nil) ? @" not found" : @" found",
(alt_method == nil) ? @" not found" : @" found");
}
} else {
NSLog(@"SwapMethods Error: Class not found");
}
}
/**
* Class extension: CWExtensions
* Overriding load so that I can swap out 3rd party framework methods
* for my own
*/
#import <ThirdPartyFramework/ThirdPartyFramework>
#import "MockDataManager.h"
#import <objc/runtime.h>
#import <objc/message.h>
@interface ThirdPartyFramework (CWExtensions)
@end
#import "ThirdPartyFramework+CWExtensions.h"
@implementation ThirdPartyFramework (CWExtensions)
+ (void)load {
#if USEMOCKOBJECTS
SwapMethodsForDifferentClass([self class], @selector(logInWithUserName:password:), [MockDataManager class], @selector(loadLoginResponse), YES);
#endif
}
@end
// MockDataManager
@interface MockDataManager : NSObject
+ (MockDataManager *)sharedManager;
- (LoginResponse *)loadLoginResponse;
@end
static NSString* const loginResponseFile = @"LoginResponse";
static char const *fileQueueName = "com.corywiles.file.handler.queue";
static dispatch_queue_t _fileQueue;
@implementation EPBMockDataManager
static MockDataManager *shared = nil;
+ (void)initialize {
_fileQueue = dispatch_queue_create(fileQueueName, 0);
}
+ (MockDataManager *)sharedManager {
static dispatch_once_t pred;
dispatch_once(&pred, ^{
shared = [[EPBMockDataManager alloc] init];
});
return shared;
}
- (id)init {
self = [super init];
if (self) {
}
return self;
}
- (LoginResponse *)loadLoginResponse {
__block LoginResponse *__obj = nil;
if (__obj == nil) {
__block NSData *jsonData;
__block NSDictionary *objDictionary = @{};
NSString *path = [[NSBundle mainBundle] pathForResource:loginResponseFile ofType:@"json"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:path];
NSAssert(fileExists, @"The path for %@ must exist", loginResponseFile);
dispatch_async(_fileQueue, ^{
jsonData = [NSData dataWithContentsOfFile:path];
objDictionary = [NSDictionary dictionaryJSONFromData:jsonData];
});
dispatch_sync(_fileQueue, ^{
__obj = [[LoginResponse alloc] initWithJSONDictionary:objDictionary];
});
if (!__obj) {
return nil;
}
}
return __obj;
}
@end
// view controller that has vendors code
// if you set the preprocessor then swizzle method is called
// no need to if/else to use your test method
ThirdPartyFramework *ws = [ThirdPartyFramework sharedManager];
LoginResponse *loginResponse = [ws logInWithUserName:@"xxxx" password:@"xxxx"];
EPBLog(@"loginResponse: %@", loginResponse);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment