Swift & Objective-C

Objective-C nil vs Java null: Why Do They Behave Differently?

There’s one thing that really confuses developers new to iOS.

4 min read
Cover image for Objective-C nil vs Java null: Why Do They Behave Differently?

There’s one thing that really confuses developers new to iOS.

In Java or C++, trying to do something with a nil (null) object immediately crashes the app. That famous NullPointerException.

But in Objective-C, sending a message to nil is silent. There’s no crash and no error.

At first, you may think, “Isn’t this a bug?” But the language was actually designed this way on purpose.

In short, sending a message to nil in Objective-C does nothing and simply returns 0 (or nil).

This isn’t leaving mistakes unchecked; it’s a deliberate safety mechanism built into the language.

Today, let’s look at why this behavior is possible and how to think about it.


Why doesn’t sending a message to nil crash?

The key lies in how Objective-C sends messages.

When we write code like [object doSomething], the compiler turns it into a function call named objc_msgSend(object, @selector(doSomething)).

Rather than calling a method directly, the code asks the runtime, “Please deliver this message to this object.”

But the objc_msgSend function first checks whether the receiving object is nil.

The point where objc_msgSend silently swallows nil
The point where objc_msgSend silently swallows nil

What if the receiving object is nil?

It doesn’t look for the method. It immediately returns 0 and quietly finishes.

In other words, nil is something that “swallows messages.” Since the message never reaches anywhere, nothing crashes.

// receiverif nildoes not look for the method and immediately 0 return
NSString *name = nil;
NSUInteger len = [name length];  // without a crash len == 0

How is this different from NullPointerException?

This is a common source of confusion, so I’ve summarized it in a table.

Category Objective-C (nil) Java (null)
Calling a method on null Ignore it and return 0/nil Throw NullPointerException
App behavior Continues without crashing Crashes with an exception
Handled by Runtime (objc_msgSend) JVM exception handling

The moment Java accesses a null reference, it throws an exception as if saying, “That object doesn’t exist.”

By contrast, the Objective-C runtime treats nil as a normal value.

That difference can feel awkward for a while when Java developers move to Objective-C.

Return values also vary slightly by type. An object type returns nil, a numeric type returns 0, and a struct returns a zero-filled value.


Is not crashing always a good thing?

Honestly, it’s a double-edged sword.

The advantage is clear: you don’t have to cover your code in nil checks.

For example, even if an empty array causes nil to be returned, asking it for count simply produces 0, so the flow doesn’t stop.

But that same feature can also become a trap.

Bugs don’t appear as crashes; they quietly get buried.

When data doesn’t appear on screen and you spend a long time investigating, it’s often because an object became nil somewhere in the middle and all its messages were ignored.

A crash would make the problem easy to find, but silently moving on makes tracing the cause take longer.

A quick run confirms whether it really doesn’t crash
A quick run confirms whether it really doesn’t crash

It’s important to develop the habit of distinguishing places where nil can safely flow from places where a value is required.


How should you handle it in practice?

Here are a few approaches I use.

  1. Explicitly check nil at important branches (if (object == nil))
  2. Mark methods that may return nil in comments or names.
  3. If an unexpected nil is suspected, catch it during development with NSAssert.

Things become different again when you move to Swift.

Swift uses the concept of Optional to make the possibility of nil explicit in the type system.

Values that may be nil must be marked with a question mark, and they must be handled safely when unwrapped.

In a sense, Swift turns Objective-C’s “silently move on” into “make it visible up front.”

Comparing it side by side with Swift reveals the difference in design philosophy
Comparing it side by side with Swift reveals the difference in design philosophy

Objective-C not crashing on messages to nil isn’t a bug; it’s a philosophy.

Because convenience can also hide silent bugs, understanding “Why doesn’t it crash?” helps you write more robust code.

If you’re seeing an unexplained blank screen in your iOS code, check whether nil is quietly passing through somewhere. It will likely help.