Created
July 25, 2013 14:21
-
-
Save markd2/6080158 to your computer and use it in GitHub Desktop.
Support file for Inside the Bracket part 7, adding some methods to classes at runtime.
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
// Add some methods with the runtime. | |
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
// clang -g -fobjc-arc -Wall -framework Foundation -o addstuff addstuff.m | |
@interface Glorn : NSObject | |
@end | |
@implementation Glorn | |
+ (BOOL) resolveInstanceMethod: (SEL) selector { | |
// Refuse this one so we get the "nobody here" exception. | |
if (sel_isEqual(selector, @selector(larvoid))) return NO; | |
// Don't want to handle anything that takes arguments. | |
if (strchr(sel_getName(selector), ':')) return NO; | |
IMP blockImp = | |
imp_implementationWithBlock ((__bridge void *) ^(id self) { | |
NSLog (@"you just called %@", | |
NSStringFromSelector(selector)); | |
}); | |
class_addMethod ([self class], selector, blockImp, "v@:"); | |
return YES; | |
} // resolveInstanceMethod | |
@end | |
@interface Glorn (HushTheCompiler) | |
- (NSString *) larvoid; | |
- (NSString *) greetingWithCount: (NSUInteger) count; | |
- (void) keep; | |
- (void) watching; | |
- (void) theSkies; | |
@end | |
static NSString *Larvoid (id self, SEL _cmd) { | |
return @"Zogg"; | |
} // Larvoid | |
void AddSomeMethods (void) { | |
Glorn *glorn = [Glorn new]; | |
NSString *name; | |
// See that it breaks; | |
@try { | |
name = [glorn larvoid]; | |
} | |
@catch (id thing) { | |
NSLog (@"got expected exception"); | |
} | |
// Add a method with a function pointer | |
Class glornClass = [Glorn class]; | |
BOOL success = class_addMethod (glornClass, @selector(larvoid), (IMP)Larvoid, "@:v"); | |
if (!success) { | |
printf ("phooey, couldn't add method\n"); | |
return; | |
} | |
name = [glorn larvoid]; | |
NSLog (@"Hello my name is %@", name); | |
// Add a method with a block | |
IMP blockImp = | |
imp_implementationWithBlock ((__bridge void *) | |
^(id self, NSUInteger count) { | |
for (NSUInteger i = 0; i < count; i++) { | |
NSLog (@"Hello #%ld, %@", i, name); | |
} | |
}); | |
char *encoding; | |
asprintf(&encoding, "v@:%s", @encode(NSUInteger)); | |
success = class_addMethod (glornClass, @selector(greetingWithCount:), | |
blockImp, encoding); | |
free (encoding); | |
if (!success) { | |
printf ("lame, couldn't add the block imp\n"); | |
return; | |
} | |
[glorn greetingWithCount: 5]; | |
[glorn keep]; | |
[glorn watching]; | |
[glorn theSkies]; | |
} // AddSomeMethods | |
int main (void) { | |
@autoreleasepool { | |
AddSomeMethods (); | |
} | |
return 0; | |
} // void | |
#if 0 | |
-[Glorn larvoid]: unrecognized selector sent to instance 0x1050142b0 | |
got expected exception | |
Hello my name is Zogg | |
Hello #0, Zogg | |
Hello #1, Zogg | |
Hello #2, Zogg | |
Hello #3, Zogg | |
Hello #4, Zogg | |
you just called who | |
you just called goes | |
you just called there | |
you just called _doZombieMe | |
(_doZombieMe was totally unexpected) | |
#0 +[Glorn resolveInstanceMethod:] (self=0x100003518, _cmd=0x7fff8cf433d3, selector=0x7fff8b59ec3c) at addstuff.m:23 | |
#1 0x00007fff8a38db9b in _class_resolveMethod () | |
#2 0x00007fff8a38b35e in lookUpMethod () | |
#3 0x00007fff8a38da5c in class_respondsToSelector () | |
#4 0x00007fff8b44d051 in -[NSObject dealloc] () | |
#5 0x00000001000016f6 in AddSomeMethods () at addstuff.m:93 | |
#6 0x000000010000189d in main () at addstuff.m:100 | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment