Show Menu

Looking for an iOS Developer?

Submit your 30 day Job Listing for FREE

iOS development tutorial with ruby

Nil messaging in Objective-C has a fairly well document behavior. In brief, messaging nil has no effect and the return value from a message sent to nil is discussed in the Programming with Objective-C

If you expect a return value from a message sent to nil, the return value will be nil for object return types, 0 for numeric types, and NO for BOOL types.

This is a very handy feature of Objective-C that might seem at first unfamiliar to Ruby programmers. In fact, invoking a method on nil in Ruby gives aNoMethodError as following:

NoMethodError: undefined method `length' for nil:NilClass

It’s a very different behavior from Objective-C that many Ruby programmers have come to rely on. I myself prefer the way nil is handled in Objective-C but let’s assume for a second that we wanted to achieve the Ruby behavior in Objective-C.

Needless to say that it is probably a very bad idea but since it could be fun, let’s have a look at the Objective-C runtime and give it a try!

We first need to find which part of the runtime is in charge of handling messages to nil. As described very nicely in this post, a message to nil is handled directly in objc_msgSend.

Given that the Objective-C runtime is open-source, we can have a look at the objc_msgSend implementation for x86_64. It is assembly but, trust me, it is fairly readable.

Our first step is to find the entry point of objc_msgSend that looks as following:

ENTRY   _objc_msgSend
DW_START _objc_msgSend


GetIsaFast NORMAL       // r11 = self->isa
CacheLookup NORMAL, _objc_msgSend  // r11=method, eq set (nonstret fwd)
jmp *method_imp(%r11)   // goto *imp

We can quickly notice that one of the first instruction is a NilTest macro that itself looks as following:

.macro NilTest
.if $0 != STRET
    testq   %a1, %a1
    testq   %a2, %a2
    jz  LNilTestSlow_f

.macro NilTestSupport
    .align 3
.if $0 != STRET
    movq    __objc_nilReceiver(%rip), %a1
    testq   %a1, %a1    // if (receiver != nil)
    movq    __objc_nilReceiver(%rip), %a2
    testq   %a2, %a2    // if (receiver != nil)
    jne LNilTestDone_b  //   send to new receiver

.if $0 == FPRET
.elseif $0 == FP2RET
.if $0 != STRET
    xorl    %eax, %eax
    xorl    %edx, %edx
    xorps   %xmm0, %xmm0
    xorps   %xmm1, %xmm1

After a few tests for the return type (struct and floating-point need special handling), we can notice that a nil receiver, if set (not nil) is given a chance to act as the message receiver. Otherwise, a few registers usually holding return values are clean and the function returns.

The __objc_nilReceiver is not usually set but if we found a way to set it to an object that we create we could alter the behavior of nil messaging!

Luckily, objc-private.h declares the following function:

extern id _objc_setNilReceiver(id newNilReceiver);

That’s it, if we call this function with our custom object we will able to intercept any message to nil.

Our NilCatcher class will only need to implement two methods methodSignatureForSelector: and forwardInvocation:. Since our implementation of forwardInvocation: won’t actually need a valid NSMethodSignature we will return the method signature of a basic method on NSObject in methodSignatureForSelector:. Eventually, we will throw an exception in forwardInvocation:, logging the selector.

Instead of adding a new class in our Xcode project we will create the class at runtime and provide a couple of method implementations with Objective-C blocks, just because it quicker and more fun. The code is shown below but also available as a gist which should be slightly easier to read.

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();
        [(id)nil isEqualToString:@"Cat"];
    return 0;

And that’s it! If you build and run you should crash on anNSInternalInconsistencyException when attempting to messaging nil, which should make any Rubyist feel at home! 😉

I cannot stress enough on the fact that you should probably never even think of using this. The Cocoa frameworks surely rely heavily on nil messaging being allowed and having no effect.

That said, it was a fun experiment and I hope you learnt something new.

having issues?

We have a Questions and Answer section where you can ask your iOS Development questions to thousands of iOS Developers.

Ask Question

FREE Download!

Get your FREE Swift 2 Cheat Sheet and quick reference guide PDF download when you sign up to SwiftMonthly

Sharing is caring

If you enjoyed this tutorial, please help us and others by sharing using one of the social media buttons below.

Written by:

I’m Damien DeVille, a software engineer working at Realmac Software in sunny Brighton, UK. I build Ember for Mac. I mostly work on Cocoa projects but enjoy some web development once in a while. I am also a real debugger aficionado. I’m also an avid reader and very passionate about languages and linguistics. I graduated from UCL with a double MSc in Computer Science and Financial Engineering