Last active
August 29, 2015 13:56
-
-
Save kylesluder/9011713 to your computer and use it in GitHub Desktop.
An Objective-C analogue to the Python super class.
This file contains hidden or 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
// % clang -framework Foundation -o ObjCSuper ObjCSuper.m SuperTrampoline.s | |
// % ./ObjCSuper | |
// | |
// 2014-02-15 23:03:32.498 ObjCSuper[1296:507] Subclass impl | |
// 2012014-02-15 23:03:32.498 ObjCSuper[1296:507] Subclass impl4-02-15 23:03:32.500 ObjCSuper[1296:507] b respondsToSelector:@selector(retain)? YES | |
// 2014-02-15 23:03:32.500 ObjCSuper[1296:507] b respondsToSelector:@selector(subclassMethod)? YES | |
// 2014-02-15 23:03:32.501 ObjCSuper[1296:507] Superclass impl | |
// 2014-02-15 23:03:32.501 ObjCSuper[1296:507] b_super respondsToSelector:@selector(retain)? YES | |
// 2014-02-15 23:03:32.501 ObjCSuper[1296:507] b_super respondsToSelector:@selector(subclassMethod)? NO | |
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
#import <objc/message.h> | |
@interface ObjCSuper : NSProxy | |
- (id)initWithTarget:(id)target; | |
- (id)initWithTarget:(id)target superclass:(Class)superclass; | |
@end | |
@implementation ObjCSuper | |
{ | |
@package | |
struct objc_super _super; | |
} | |
- (instancetype)initWithTarget:(id)target; | |
{ | |
return [self initWithTarget:target superclass:[target superclass]]; | |
} | |
- (instancetype)initWithTarget:(id)target superclass:(Class)superclass; | |
{ | |
_super.receiver = [target retain]; | |
_super.super_class = [superclass retain]; | |
return self; | |
} | |
- (void)dealloc; | |
{ | |
[_super.receiver release]; | |
[_super.super_class release]; | |
[super dealloc]; | |
} | |
- (BOOL)respondsToSelector:(SEL)sel; | |
{ | |
return class_getInstanceMethod(_super.super_class, sel) != NULL || [[self class] instancesRespondToSelector:sel]; | |
} | |
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel; | |
{ | |
return [_super.receiver methodSignatureForSelector:sel]; | |
} | |
extern id _trampolineImp(id self, SEL _cmd, ...); | |
- (void)forwardInvocation:(NSInvocation *)inv; | |
{ | |
SEL sel = [inv selector]; | |
Class targetClass = [_super.receiver class]; | |
Method targetMethod = class_getInstanceMethod(targetClass, sel); | |
NSAssert(targetMethod != nil, @"cannot find instance method for selector %@ of target <%@:%p>", NSStringFromSelector(sel), targetClass, _super.receiver); | |
class_addMethod([self class], sel, _trampolineImp, method_getTypeEncoding(targetMethod)); | |
[inv setTarget:self]; | |
[inv invoke]; | |
} | |
@end | |
#pragma mark - Test | |
@interface Foo : NSObject | |
- (void)someMethod; | |
@end | |
@implementation Foo | |
- (void)someMethod; | |
{ | |
NSLog(@"Superclass impl"); | |
} | |
@end | |
@interface Bar : Foo | |
- (void)subclassMethod; | |
@end | |
@implementation Bar | |
- (void)someMethod; | |
{ | |
NSLog(@"Subclass impl"); | |
} | |
- (void)subclassMethod; | |
{ | |
NSLog(@"Subclass only method"); | |
} | |
@end | |
int main(int argc, char **argv) | |
{ | |
@autoreleasepool { | |
Bar *b = [Bar new]; | |
[b someMethod]; | |
NSLog(@"b respondsToSelector:@selector(retain)? %@", [b respondsToSelector:@selector(retain)] ? @"YES" : @"NO"); | |
NSLog(@"b respondsToSelector:@selector(subclassMethod)? %@", [b respondsToSelector:@selector(subclassMethod)] ? @"YES" : @"NO"); | |
Foo *b_super = (Foo *)[[ObjCSuper alloc] initWithTarget:b]; | |
[b_super someMethod]; | |
NSLog(@"b_super respondsToSelector:@selector(retain)? %@", [b respondsToSelector:@selector(retain)] ? @"YES" : @"NO"); | |
NSLog(@"b_super respondsToSelector:@selector(subclassMethod)? %@", [b_super respondsToSelector:@selector(subclassMethod)] ? @"YES" : @"NO"); | |
[b_super release]; | |
[b release]; | |
} | |
return 0; | |
} |
This file contains hidden or 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
// IMP _trampolineImp; | |
// | |
// args: | |
// %rdi: pointer to ObjCSuper instance | |
.text | |
.globl __trampolineImp | |
.align 4, 0x90 | |
__trampolineImp: | |
movq _OBJC_IVAR_$_ObjCSuper._super(%rip), %r11 | |
leaq (%rdi, %r11), %rdi | |
jmpq *_objc_msgSendSuper@GOTPCREL(%rip) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment