Created
September 21, 2012 15:15
-
-
Save kwylez/3762103 to your computer and use it in GitHub Desktop.
Method Swizzling
This file contains 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
// 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