Namespacing in Objective-C - The Prefix Problem
Swift has modules. C++ has namespaces. Java has packages. Objective-C has... three-letter prefixes. It's not elegant, but it works. Here's how the community solved namespace collisions without language-level support.
The Problem
Every class name in Objective-C shares a single global namespace. If your app and a third-party library both define a User class, you have a collision. The linker picks one, and code expecting the other breaks in confusing ways.
// Your code
@interface User : NSObject
@property (nonatomic, copy) NSString *email;
@end
// Some analytics SDK also defines
@interface User : NSObject
@property (nonatomic, copy) NSString *sessionId;
@end
// Collision - only one survives linking
The Prefix Convention
Apple's solution: every class name starts with a prefix. Apple reserves two-letter prefixes for themselves (NS, UI, CG, CA, AV, etc.), and third-party developers use three or more letters.
// Apple's Foundation
@interface NSString : NSObject
// Your company (Acme Corp)
@interface ACMUser : NSObject
// Another library (Bob's SDK)
@interface BOBUser : NSObject
Three classes, no collision, everyone happy.
Choosing a Prefix
Pick something distinctive. Common approaches include using your company initials, project name, or product name. Just check that nobody else is using it.
Bad choices:
XXX- Too generic, probably already usedAPP- Same problemNS,UI,CF- Reserved by Apple
Good choices:
ACMfor Acme CorporationNYTfor New York TimesAFNfor AFNetworking (the library's initials)
Some projects use longer prefixes for extra safety: Parse used PF, Cocoapods recommends your pod name.
Categories Need Prefixes Too
Class names aren't the only collision risk. Categories can clash:
// Two different libraries both add -jsonValue to NSString
@interface NSString (MyJSON)
- (id)jsonValue;
@end
@interface NSString (TheirJSON)
- (id)jsonValue; // Collision!
@end
Category method collisions are worse than class collisions. With classes, you get a linker warning. With categories, one silently replaces the other.
The fix: prefix category method names too:
@interface NSString (ACM_JSON)
- (id)acm_jsonValue;
@end
Ugly? Yes. Necessary? Absolutely.
Constants and Enums
Global constants and enums share the same flat namespace:
// Bad - will clash
typedef NS_ENUM(NSInteger, Status) {
StatusPending,
StatusComplete
};
// Good - prefixed
typedef NS_ENUM(NSInteger, ACMOrderStatus) {
ACMOrderStatusPending,
ACMOrderStatusComplete
};
The NS_ENUM macro helps by requiring the type name in each value, but you still need the prefix on the type.
Functions and Global Variables
C functions and global variables need prefixes too:
// Bad
void processData(NSData *data);
extern NSString *currentVersion;
// Good
void ACMProcessData(NSData *data);
extern NSString *ACMCurrentVersion;
In practice, prefer class methods or constants to global functions and variables. They're scoped to their class, reducing collision surface.
The Static Approach
For internal use, static limits visibility to a single file:
// Only visible in this .m file
static NSString *const kDefaultTimeout = @"30";
static void helperFunction(void) {
// ...
}
Static symbols don't need prefixes because they can't collide with other files.
Class Extensions vs Prefixed Interfaces
Sometimes you want to keep methods out of the public header but still define them formally. Class extensions (anonymous categories) help:
// ACMUser.m
@interface ACMUser ()
@property (nonatomic, copy) NSString *internalToken;
- (void)performSecretOperation;
@end
@implementation ACMUser
// ...
@end
The extension methods are private to your implementation, so they don't need aggressive prefixing.
Swift's Solution
When Swift came along, Apple finally added proper namespacing through modules. Each framework or app is its own module, and you reference external types with the module prefix when needed:
// Swift
import MyFramework
let user = MyFramework.User() // Explicit
let user = User() // Works if unambiguous
Objective-C code compiled as a module gets similar benefits. The @import syntax respects module boundaries, though class names still exist in the global namespace for compatibility.
Living with Prefixes
After decades, the prefix convention is deeply ingrained. Libraries like AFNetworking (AF), Masonry (MAS), and SDWebImage (SD) are immediately recognizable by their prefixes. It's become part of the culture.
Is it perfect? No. But it's simple, consistent, and has survived thirty-plus years of Objective-C development. Sometimes the obvious solution—even an ugly one—beats a clever alternative that nobody uses.
When in doubt, prefix everything visible outside your implementation file. Your future self, debugging a mysterious symbol collision at 2 AM, will thank you.