I am a little confused as to when it\'s best to use:
static NSString *AppQuitGracefullyKey = @\"AppQuitGracefully\";
instead of
If you use a static, the compiler will embed exactly one copy of the string in your binary and just pass pointers to that string around, resulting in more compact binaries. If you use a #define, there will be a separate copy of the string stored in the source on each use. Constant string coalescing will handle many of the dups but you're making the linker work harder for no reason.
USING #define :
you can't debug the value of identifier
work with #define and other macros is a job of Pre-Processor, When you hit Build/Run first it will preprocess the source code, it will work with all the macros(starting with symbol #),
Suppose, you have created,
#define LanguageTypeEnglish @"en"
and used this at 2 places in your code.
NSString *language = LanguageTypeEnglish;
NSString *languageCode = LanguageTypeEnglish;
it will replace "LanguageTypeEnglish" with @"en"
, at all places.
So 2 copies of @"en"
will be generated.
i.e
NSString *language = @"en";
NSString *languageCode = @"en";
Remember, till this process, compiler is not in picture.
After preprocessing all the macros, complier comes in picture, and it will get input code like this,
NSString *language = @"en";
NSString *languageCode = @"en";
and compile it.
USING static :
it respects scope and is type-safe. you can debug the value of identifier
During compilation process if compiler found,
static NSString *LanguageTypeRussian = @"ru";
then it will check if the variable with the same name stored previously, if yes, it will only pass the pointer of that variable, if no, it will create that variable and pass it's pointer, next time onwards it will only pass the pointer of the same.
So using static, only one copy of variable is generated within the scope.
After doing some search (this question/answer among other things) I think it is important to say that anytime when you are using string literal @"AppQuitGracefully"
constant string is created, and no matter how many times you use it it will point to the same object.
So I think (and I apologize me if I'm wrong) that this sentence in above answer is wrong: If you use a #define, there will be a separate copy of the string stored in the source on each use.
I use static
when I need to export NSString symbols from a library or a framework. I use #define
when I need a string in many places that I can change easily. Anyway, the compiler and the linker will take care of optimizations.
I actually would recommend neither, you should use extern
instead. Objective-c already defines FOUNDATION_EXPORT
which is more portable than extern
, so a global NSString
instance would look something like this:
.h
FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey;
.m
NSString * const AppQuitGracefullyKey = @"AppQuitGracefully";
I usually put these in declaration files (such as MyProjectDecl.h
) and import whenever I need.
There are a few differences to these approaches:
#define ((int)1)
) but what's the point? And besides, there are debugging disadvantages to that approach. Compilers prefer constants. See this discussion.Static and extern differ in visibility. It's also notable that neither of these approaches duplicates the string (not even #define
) as the compiler uses String Interning to prevent that. In this NSHipster post they show proof:
NSString *a = @"Hello";
NSString *b = @"Hello";
BOOL wtf = (a == b); // YES
The operator ==
returns YES
only if the two variables point at the same instance. And as you can see, it does.
The conclusion is: use FOUNDATION_EXPORT
for global constants. It's debug friendly and will be visible allover your project.
See "static const" vs "#define" vs "enum". The main advantage of static
is type safety.
Other than that, the #define
approach introduces a flexibility of inline string concatenation which cannot be done with static variables, e.g.
#define ROOT_PATH @"/System/Library/Frameworks"
[[NSBundle bundleWithPath:ROOT_PATH@"/UIKit.framework"] load];
but this is probably not a good style :).