Skip to content

Instantly share code, notes, and snippets.

@levey
Forked from ddeville/ruby-nil-messaging-objc.m
Created July 5, 2013 07:55
Show Gist options
  • Save levey/5932791 to your computer and use it in GitHub Desktop.
Save levey/5932791 to your computer and use it in GitHub Desktop.
//
// 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