NS: Poor Man’s Namespacing for Objective-C

Objective-C unfortunately lacks namespaces. This leads to both compile-time woes and runtime woes. You may have been witness to this runtime warning:

Class SUUpdater is implemented in both MyApp.app/Contents/Frameworks/Sparke and MyAppPlugin. One of the two will be used. Which one is undefined.

While Kyle Sluder has been leading the charge towards getting the feature as a first-class citizen in Objective-C, I’ve been successfully using a nine-line preprocessor hack for a few years now that effectively works-around the problem. I call it NS:

#ifndef NS
    #ifdef NS_NAMESPACE
        #define JRNS_CONCAT_TOKENS(a,b) a##_##b
        #define JRNS_EVALUATE(a,b) JRNS_CONCAT_TOKENS(a,b)
        #define NS(original_name) JRNS_EVALUATE(NS_NAMESPACE, original_name)
    #else
        #define NS(original_name) original_name
    #endif
#endif

Instead of writing your classes like so:

@interface Person : NSObject
@property(strong) NSString *name;
@end

Write it like so:

@interface NS(Person) : NSObject
@property(strong) NSString *name;
@end
#define Person NS(Person)

Then use the class like you normally would:

Person *p = [Person new];

Now your code supports compile-time prefix insertion. If you don’t do anything else, your classes will remain unprefixed.

However, you can now prefix all participating classes with one easy flick of a preprocessor definition:

-D NS_NAMESPACE=MyFramework

That turns the code above into:

MyFramework_Person *p = [MyFramework_Person new];

With judicious targeting of your -D NS_NAMESPACE= use, this should enable you to work-around class collisions at both compile-time and runtime.

P. S. I recognize it’s probably a bad idea for me to squat on something as Apple-generic as NS, but I don’t care.

Update: Uli Kusterer points out this hack doesn’t cover XIBs, since they reference classes by name and avoid the preprocessor’s reach.

I’ve only used this technique with pure code libraries, so that limitation hasn’t bitten me.

cocoa ns Jan 17 2013