mick@next:~/objc/namespacing-objc$/* Rediscovering the language that built the future */
Namespacing in Objective-C - The Prefix Problem
objc / namespacing-objc.m

Namespacing in Objective-C - The Prefix Problem

Mick MacCallumMick MacCallum
@Objective-C@Best Practices@Architecture

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 used
  • APP - Same problem
  • NS, UI, CF - Reserved by Apple

Good choices:

  • ACM for Acme Corporation
  • NYT for New York Times
  • AFN for 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.