When to use static string vs. #define

前端 未结 6 1808
-上瘾入骨i
-上瘾入骨i 2021-01-30 10:49

I am a little confused as to when it\'s best to use:

static NSString *AppQuitGracefullyKey = @\"AppQuitGracefully\";

instead of



        
相关标签:
6条回答
  • 2021-01-30 11:01

    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.

    0 讨论(0)
  • 2021-01-30 11:02

    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.

    0 讨论(0)
  • 2021-01-30 11:03

    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.

    0 讨论(0)
  • 2021-01-30 11:17

    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.

    0 讨论(0)
  • 2021-01-30 11:20

    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 has several downsides, such as not being type safe. It is true that there are workarounds for that (such as #define ((int)1)) but what's the point? And besides, there are debugging disadvantages to that approach. Compilers prefer constants. See this discussion.
    • static globals are visible in the file they are declared.
    • extern makes the variable visible to all files. That contrasts with static.

    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.

    0 讨论(0)
  • 2021-01-30 11:22

    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 :).

    0 讨论(0)
提交回复
热议问题