160
votes

I am creating a Reddit client for learning purposes. I need to have a file with constants in it. I was thinking about importing the file in the Reddit-Prefix.pch file to make the constants available to all the files. Is it a good way of doing things? Also, I've done my research and found several methods to create constants, but I don't know which one to use:

  • #define macro
  • const
  • static const
  • extern const
  • enum

So which way is the preferred way? What is the convention? I know that "it depends" but my question more specifically is: What are the use cases for each of those solutions?

Also, if using extern const, do I need to import the file, or the constants will be available globally without importing the file?

One thing I could logically conclude is that enum is the best choice when defining something like custom error domains (am I actually right?). But what about the others?

2
stackoverflow.com/questions/11153156/… please visit this link...your solution is in this postUser 1531343
@BhavikKama: That's a narrower question contrasting two specific solutions.Peter Hosey
for - static const, #define , enum , this link is usefull stackoverflow.com/questions/1674032/static-const-vs-define-in-c that provides good explanation on those 3 alternative of constUser 1531343
enum is only useful for integral values. #define and constants can be any data type.rmaddy
const, static const, and extern const are all the same except for scope. So there are really only three choices.rmaddy

2 Answers

392
votes

The first question is what scope you want your constants to have, which is really two questions:

  • Are these constants specific to a single class, or does it make sense to have them all over the application?
  • If they are class-specific, are they for use by clients of the class, or only within the class?

If they are specific and internal to a single class, declare them as static const at the top of the .m file, like so:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

If they pertain to a single class but should be public/used by other classes, declare them as extern in the header and define them in the .m:

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

If they should be global, declare them in a header and define them in a corresponding module, specifically for those constants.

You can mix and match these for different constants with different levels of how global you want them to be, and for different global constants that simply don't belong together—you can put them in separate modules, each with its own header, if you want.

Why not #define?

The old answer is “macros don't have type information”, but compilers today are pretty smart about doing all the type-checking for literals (what macros expand to) as well as variables.

The modern answer is because the debugger won't know about your macros. You can't say [myThing addObserver:self forKey:MyThingNotificationKey] in a debugger command if MyThingNotificationKey is a macro; the debugger can only know about it if it is a variable.

Why not enum?

Well, rmaddy beat me to it in the comments: enum can only define integer constants. Things like serial identifier numbers, bit-masks, four-byte codes, etc.

For those purposes, enum is great and you absolutely should use it. (Even better, use the NS_ENUM and NS_OPTIONS macros.) For other things, you must use something else; enum does not do anything but integers.

And other questions

I was thinking about importing the file in the Reddit-Prefix.pch file to make the constants available to all the files. Is it a good way of doing things?

Probably harmless, but probably excessive. Import your constants header(s) where you need them.

What are the use cases for each of those solutions?

  • #define: Pretty limited. I'm honestly not sure there's a good reason to use this for constants anymore.
  • const: Best for local constants. Also, you have to use this for one you declared in a header and are now defining.
  • static const: Best for file-specific (or class-specific) constants.
  • extern const: You must use this when exporting a constant in a header.

Also, if using extern const, do I need to import the file, or the constants will be available globally without importing the file?

You need to import the file, either in each file where you use it or in the prefix header.

9
votes

FOUNDATION_EXPORT

Consider using FOUNDATION_EXPORT for a bit more compatibility than extern since it is defined in foundation and compiles to compatible formats for C, C++, and Win32.

As defined in NSObjCRuntime.h

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif

#if TARGET_OS_WIN32

    #if defined(NSBUILDINGFOUNDATION)
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
    #else
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
    #endif

    #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)

#else
    #define FOUNDATION_EXPORT  FOUNDATION_EXTERN
    #define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif