Created
June 28, 2013 14:00
-
-
Save ddeville/5884869 to your computer and use it in GitHub Desktop.
Ruby-like nil messaging in Objective-C
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
// | |
// Created by Damien DeVille on 6/23/13. | |
// Copyright (c) 2013 Damien DeVille. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
extern id _objc_setNilReceiver(id newNilReceiver); | |
static id _createNilCatcherObject(void) | |
{ | |
Class NilCatcher = objc_allocateClassPair([NSObject class], "NilCatcher", 0); | |
NSMethodSignature * (^methodSignatureForSelectorBlock)(id, SEL) = ^ NSMethodSignature * (id _block, SEL selector) { | |
/* | |
We will not actually use the method signature in forwardInvocation so any signature will do it. | |
*/ | |
return [NSObject instanceMethodSignatureForSelector:@selector(description)]; | |
}; | |
IMP methodSignatureForSelectorIMP = imp_implementationWithBlock(methodSignatureForSelectorBlock); | |
Method methodSignatureForSelectorMethod = class_getClassMethod([NSObject class], @selector(methodSignatureForSelector:)); | |
class_addMethod(NilCatcher, @selector(methodSignatureForSelector:), methodSignatureForSelectorIMP, method_getTypeEncoding(methodSignatureForSelectorMethod)); | |
void (^forwardInvocationBlock)(id, NSInvocation *) = ^ void (id _block, NSInvocation * invocation) { | |
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"Attempting to message %s to nil", sel_getName([invocation selector])] userInfo:nil]; | |
}; | |
IMP forwardInvocationIMP = imp_implementationWithBlock(forwardInvocationBlock); | |
Method forwardInvocationMethod = class_getClassMethod([NSObject class], @selector(forwardInvocation:)); | |
class_addMethod(NilCatcher, @selector(forwardInvocation:), forwardInvocationIMP, method_getTypeEncoding(forwardInvocationMethod)); | |
return [NilCatcher new]; | |
} | |
int main(int argc, const char **argv) | |
{ | |
@autoreleasepool { | |
id nilCatcher = _createNilCatcherObject(); | |
_objc_setNilReceiver(nilCatcher); | |
[(id)nil isEqualToString:@"Cat"]; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment