Created
July 25, 2013 14:18
-
-
Save markd2/6080126 to your computer and use it in GitHub Desktop.
Support file for Inside the Bracket, part 7, the final chapter, part two. This time, it's 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
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
// clang -g -fobjc-arc -Wall -framework Foundation -o swizzle swizzle.m | |
// Swap two methods | |
void SwizzleMethod (Class clas, SEL originalSelector, SEL newSelector) { | |
Method originalMethod = | |
class_getInstanceMethod (clas, originalSelector); | |
Method newMethod = | |
class_getInstanceMethod (clas, newSelector); | |
BOOL addedMethod = | |
class_addMethod (clas, originalSelector, | |
method_getImplementation(newMethod), | |
method_getTypeEncoding(newMethod)); | |
if (addedMethod) { | |
class_replaceMethod (clas, newSelector, | |
method_getImplementation(originalMethod), | |
method_getTypeEncoding(originalMethod)); | |
} else { | |
method_exchangeImplementations (originalMethod, newMethod); | |
} | |
} // SwizzleMethod | |
// Naive implementation *sort* of works, but will clober the superclass if | |
// |clas| doesn't implement the original method but the super does. | |
// Don't use this. Really. It's used as an object lesson on being | |
// very careful with these tools. | |
void SwizzleMethodBadly (Class clas, SEL originalSelector, SEL newSelector) { | |
Method originalMethod = class_getInstanceMethod (clas, originalSelector); | |
Method newMethod = class_getInstanceMethod (clas, newSelector); | |
if (originalMethod && newMethod) { | |
method_exchangeImplementations (originalMethod, newMethod); | |
} else { | |
NSLog (@"no swizzle u!"); | |
} | |
} // SwizzleMethodBadly | |
// -------------------------------------------------- | |
// Say stuff from Cocoa or some library we want to hack | |
@interface BaseClass : NSObject | |
- (void) hornswoggle; | |
- (void) bamboozle; | |
- (void) doStuff; // Calls hornswoggle and bamboozle to do its work. | |
@end | |
@interface FirstBegat : BaseClass | |
// implements hornswoggle and bamboozle | |
@end | |
@interface SecondBegat : FirstBegat | |
// implements hornswoggle (not bamboozle) | |
@end | |
@implementation BaseClass | |
- (void) doStuff { | |
[self hornswoggle]; | |
[self bamboozle]; | |
} // doStuff | |
- (void) hornswoggle { | |
NSLog (@"BaseClass hornswoggle"); | |
} | |
- (void) bamboozle { | |
NSLog (@"BaseClass bamboozle"); | |
} | |
@end // BaseClass | |
@implementation FirstBegat | |
- (void) hornswoggle { | |
NSLog (@"FirstBegat hornswoggle calling"); | |
[super hornswoggle]; | |
} | |
- (void) bamboozle { | |
NSLog (@"FirstBegat bamboozle calling"); | |
[super bamboozle]; | |
} | |
@end // FirstBegat | |
@implementation SecondBegat | |
- (void) hornswoggle { | |
NSLog (@"SecondBegat hornswoggle calling"); | |
[super hornswoggle]; | |
} | |
@end // SecondBegat | |
// -------------------------------------------------- | |
// Container for the various swizzled methods | |
@interface FirstBegat (HackNSlash) | |
+ (void) hck_hijackMethods; | |
@end | |
@implementation FirstBegat (HackNSlash) | |
+ (void) hck_hijackMethods { | |
SwizzleMethod ([self class], @selector(hornswoggle), | |
@selector($hackFirstBegat_Hornswoggle)); | |
} | |
- (void) $hackFirstBegat_Hornswoggle { | |
NSLog (@"I'm in ur FirstBegat doin ur %s", sel_getName(_cmd)); | |
[self $hackFirstBegat_Hornswoggle]; // Actually calls original implementation | |
} | |
@end | |
@interface SecondBegat (HackNSlash) | |
+ (void) hck_hijackMethods; | |
@end | |
@implementation SecondBegat (HackNSlash) | |
+ (void) hck_hijackMethods { | |
SwizzleMethodBadly ([self class], @selector(bamboozle), | |
@selector($hackSecondBegat_Bamboozle)); | |
} | |
- (void) $hackSecondBegat_Bamboozle { | |
NSLog (@"I'm in ur SecondBegat doin ur %s", sel_getName(_cmd)); | |
} | |
@end | |
int main (void) { | |
@autoreleasepool { | |
FirstBegat *first = [FirstBegat new]; | |
SecondBegat *second = [SecondBegat new]; | |
NSLog (@"--------------------------------------------------"); | |
NSLog (@"FirstBegat, do stuff!"); | |
[first doStuff]; | |
NSLog (@"--------------------------------------------------"); | |
NSLog (@"SecondBegat, do stuff!"); | |
[second doStuff]; | |
NSLog (@"=================================================="); | |
[FirstBegat hck_hijackMethods]; | |
NSLog (@"FirstBegat, do stuff!"); | |
[first doStuff]; | |
NSLog (@"--------------------------------------------------"); | |
NSLog (@"SecondBegat, do stuff!"); | |
[second doStuff]; | |
NSLog (@"=================================================="); | |
[SecondBegat hck_hijackMethods]; | |
NSLog (@"FirstBegat, after bad swizzling, do stuff!"); | |
[first doStuff]; | |
NSLog (@"--------------------------------------------------"); | |
NSLog (@"SecondBegat, do stuff!"); | |
[second doStuff]; | |
} | |
return 0; | |
} // main | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment