- Published on
> nil vs Nil vs NULL vs NSNull in Objective-C
- Authors

- Name
- Mick MacCallum
- @0x7fs
Objective-C gives you four distinct ways to represent "nothing": nil, Nil, NULL, and NSNull. They look similar but serve different purposes, and confusing them leads to bugs that are surprisingly hard to track down.
nil: The Objective-C Object Pointer
nil represents a pointer to no object. It's defined as (id)0 and is what you use when dealing with Objective-C objects:
NSString *name = nil;
NSArray *items = nil;
id something = nil;
The magic of nil is that you can send messages to it without crashing. Messages to nil return zero (or the zero equivalent for the return type):
NSString *name = nil;
NSUInteger length = [name length]; // Returns 0
BOOL isEmpty = [name isEqualToString:@""]; // Returns NO (0)
NSString *upper = [name uppercaseString]; // Returns nil
This behavior simplifies code significantly. Instead of defensive nil checks everywhere, you can often let nil propagate naturally:
// This is fine even if user or user.profile is nil
NSString *bio = [[[user profile] bio] uppercaseString];
If any part of the chain is nil, the result is nil. No crash, no exception.
Nil: The Class Pointer
Nil (capital N) represents a pointer to no class. It's defined as (Class)0:
Class someClass = Nil;
Class stringClass = [NSString class];
if (someClass == Nil) {
// No class assigned
}
In practice, you rarely use Nil directly. It's the correct choice when you have a variable of type Class rather than id, but most code deals with object instances, not classes. When you do work with classes dynamically (like in runtime manipulation), Nil is technically correct:
Class cls = NSClassFromString(@"NonexistentClass");
if (cls == Nil) {
NSLog(@"Class not found");
}
That said, many codebases use nil here and the compiler doesn't complain. The distinction matters more for readability than correctness.
NULL: The C Pointer
NULL is the C null pointer, defined as (void *)0. Use it with C pointers, not Objective-C objects:
int *numbers = NULL;
char *buffer = NULL;
void *context = NULL;
You'll encounter NULL frequently when working with Core Foundation, Core Graphics, or any C API:
CGContextRef context = NULL;
CFStringRef cfString = NULL;
CGImageRef image = CGImageCreateWithJPEGDataProvider(
provider,
NULL, // decode array
true, // shouldInterpolate
kCGRenderingIntentDefault
);
In C APIs, passing NULL typically means "use the default" or "I don't need this parameter." Unlike nil, dereferencing NULL crashes immediately.
NSNull: Nothing as an Object
NSNull is fundamentally different from the others. It's not a zero value. It's an actual object that represents the concept of nothing:
NSNull *null = [NSNull null]; // A singleton object
Why would you need an object to represent nothing? Because Foundation collections can't contain nil:
// This crashes at runtime
NSArray *bad = @[@"one", nil, @"three"];
// This works
NSArray *good = @[@"one", [NSNull null], @"three"];
NSNull appears frequently when parsing JSON where null values exist:
NSDictionary *json = @{
@"name": @"Alice",
@"nickname": [NSNull null], // JSON null
@"age": @30
};
// Check for NSNull before using
id nickname = json[@"nickname"];
if (nickname == [NSNull null]) {
NSLog(@"No nickname set");
}
Since NSNull is a real object, comparing with == works because it's a singleton. Every call to [NSNull null] returns the same instance.
Common Mistakes
Confusing NSNull with nil in collection checks:
// Wrong: This checks if the key exists, not if the value is null
if (dict[@"key"] == nil) {
// Key might exist with NSNull value!
}
// Right: Check for both
id value = dict[@"key"];
if (value == nil || value == [NSNull null]) {
// Key missing or explicitly null
}
Using NULL with Objective-C objects:
// Works but wrong type
NSString *name = NULL;
// Correct
NSString *name = nil;
Sending messages to NSNull expecting nil behavior:
id value = [NSNull null];
NSString *upper = [value uppercaseString]; // Crash! NSNull doesn't respond to uppercaseString
Unlike nil, NSNull is a real object. It only responds to NSObject methods and a few others. Sending an unrecognized message crashes.
The Practical Summary
Use nil for Objective-C object pointers. This is what you'll use 95% of the time.
Use Nil for Class pointers, though nil works too if you're not being pedantic.
Use NULL for C pointers: int *, char *, void *, and Core Foundation types like CGContextRef.
Use NSNull when you need to store "nothing" in a collection or represent an explicit null value from JSON or a database.
When receiving data from external sources (network, database, JSON), always check for both nil and NSNull:
- (NSString *)safeStringFromValue:(id)value {
if (value == nil || value == [NSNull null]) {
return nil;
}
if ([value isKindOfClass:[NSString class]]) {
return value;
}
return [value description];
}
This pattern handles missing keys, explicit nulls, and type mismatches gracefully.
The four types of nothing in Objective-C reflect its heritage as a bridge between C and object-oriented programming. Understanding when to use each makes your code clearer and prevents the class of bugs where you're checking for the wrong kind of nothing.
// Continue_Learning
Blocks - Closures Before Swift Existed
Before Swift closures, Objective-C had blocks. The syntax is different, but the power is the same. Here's how to use them effectively.
The NSObject Class Hierarchy Explained
Every Objective-C class inherits from NSObject (usually). Here's what NSObject provides and why it matters for every object you create.
Categories vs Class Extensions in Objective-C
Both let you add methods to classes, but categories and class extensions serve different purposes. Here's when to use each.
// Stay Updated
Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.